From 682a47dbb23d644548b1d6ffda04618ee02e1317 Mon Sep 17 00:00:00 2001 From: Tom Copeland Date: Tue, 22 Apr 2003 15:10:05 +0000 Subject: [PATCH] Committed Philippe's latest CPD task changes git-svn-id: https://pmd.svn.sourceforge.net/svnroot/pmd/trunk@1848 51baf565-9d33-0410-a72c-fc3788e3496d --- pmd/etc/build.xml | 4 +- pmd/etc/changelog.txt | 1 + .../sourceforge/pmd/cpd/FileReporterTest.java | 72 ++++++++++ pmd/src/net/sourceforge/pmd/cpd/CPDTask.java | 133 ++++++++++-------- .../net/sourceforge/pmd/cpd/CPPLanguage.java | 2 +- .../net/sourceforge/pmd/cpd/CPPTokenizer.java | 8 +- .../net/sourceforge/pmd/cpd/FileReporter.java | 34 +++++ .../net/sourceforge/pmd/cpd/JavaLanguage.java | 2 +- .../sourceforge/pmd/cpd/ReportException.java | 11 ++ pmd/xdocs/credits.xml | 2 +- 10 files changed, 200 insertions(+), 69 deletions(-) create mode 100644 pmd/regress/test/net/sourceforge/pmd/cpd/FileReporterTest.java create mode 100644 pmd/src/net/sourceforge/pmd/cpd/FileReporter.java create mode 100644 pmd/src/net/sourceforge/pmd/cpd/ReportException.java diff --git a/pmd/etc/build.xml b/pmd/etc/build.xml index 67a0fa641b..44e53b5985 100644 --- a/pmd/etc/build.xml +++ b/pmd/etc/build.xml @@ -137,8 +137,8 @@ - - + + diff --git a/pmd/etc/changelog.txt b/pmd/etc/changelog.txt index 7a233f1c28..6a1268db49 100644 --- a/pmd/etc/changelog.txt +++ b/pmd/etc/changelog.txt @@ -1,4 +1,5 @@ ????? - 1.06: +Removed "verbose" attribute from CPD Ant task; now it uses built in logging so you can do a "ant -verbose cpd". Thanks to Philippe T'Seyen for the code. TODO - fix it so tests and rules don't duplicate the xpath expressions April 17 - 1.05: diff --git a/pmd/regress/test/net/sourceforge/pmd/cpd/FileReporterTest.java b/pmd/regress/test/net/sourceforge/pmd/cpd/FileReporterTest.java new file mode 100644 index 0000000000..7b81e8136c --- /dev/null +++ b/pmd/regress/test/net/sourceforge/pmd/cpd/FileReporterTest.java @@ -0,0 +1,72 @@ +package test.net.sourceforge.pmd.cpd; + +import junit.framework.TestCase; +import net.sourceforge.pmd.cpd.FileReporter; +import net.sourceforge.pmd.cpd.ReportException; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +/** + * @author Philippe T'Seyen + */ +public class FileReporterTest extends TestCase +{ + public void testCreation() { + try { + FileReporter fileReporter = new FileReporter(null); + fail("expected NullPointerException"); + } catch (NullPointerException npe) { + } + } + + public void testEmptyReport() throws ReportException { + File reportFile = new File("report.tmp"); + FileReporter fileReporter = new FileReporter(reportFile); + fileReporter.report(""); + assertTrue(reportFile.exists()); + assertEquals(0, reportFile.length()); + assertTrue(reportFile.delete()); + } + + public void testReport() throws ReportException, IOException { + String testString = "first line\nsecond line"; + File reportFile = new File("report.tmp"); + FileReporter fileReporter = new FileReporter(reportFile); + + fileReporter.report(testString); + assertEquals(testString, readFile(reportFile)); + assertTrue(reportFile.delete()); + } + + public void testInvalidFile() { + File reportFile = new File("/invalid_folder/report.tmp"); + FileReporter fileReporter = new FileReporter(reportFile); + try { + fileReporter.report(""); + fail("expected ReportException"); + } catch (ReportException re) { + } + } + + private String readFile(File file) throws IOException { + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(file)); + StringBuffer buffer = new StringBuffer(); + String line = reader.readLine(); + while (line != null) { + buffer.append(line); + line = reader.readLine(); + if (line != null) { + buffer.append("\n"); + } + } + return buffer.toString(); + } finally { + if (reader != null) reader.close(); + } + } +} diff --git a/pmd/src/net/sourceforge/pmd/cpd/CPDTask.java b/pmd/src/net/sourceforge/pmd/cpd/CPDTask.java index 4b83f025e2..9c84a4aec3 100644 --- a/pmd/src/net/sourceforge/pmd/cpd/CPDTask.java +++ b/pmd/src/net/sourceforge/pmd/cpd/CPDTask.java @@ -2,20 +2,17 @@ package net.sourceforge.pmd.cpd; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; +import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.FileSet; -import java.io.BufferedWriter; import java.io.File; -import java.io.FileWriter; import java.io.IOException; -import java.io.Writer; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import net.sourceforge.pmd.ant.PathChecker; - /** * CPDTask * @@ -34,65 +31,78 @@ import net.sourceforge.pmd.ant.PathChecker; * * Required: minimumTokenCount, outputFile, and at least one file * Optional: verbose - * - * TODO Perhaps come up with another renderer such as XML and - * allow user to plug that render in via ant... - * - * @since Mar 26, 2003 - * @author aglover */ public class CPDTask extends Task { - private boolean verbose; + private static final String TEXT_FORMAT = "text"; + private static final String XML_FORMAT = "xml"; + + private String format = TEXT_FORMAT; private int minimumTokenCount; - private String outputFile; + private File outputFile; private List filesets = new ArrayList(); - public void execute() throws BuildException{ - try{ - validateFields(); - CPD cpd = new CPD(minimumTokenCount, new JavaLanguage()); - for (Iterator i = filesets.iterator(); i.hasNext();) { - FileSet fs = (FileSet) i.next(); - DirectoryScanner ds = fs.getDirectoryScanner(project); - String[] srcFiles = ds.getIncludedFiles(); - for (int j = 0; j < srcFiles.length; j++) { - File file = new File(ds.getBasedir() + System.getProperty("file.separator") + srcFiles[j]); - printIfVerbose("Tokenizing " + file.getAbsoluteFile().toString()); - cpd.add(file); - } - } - printIfVerbose("Starting to analyze code "); - long start = System.currentTimeMillis(); - cpd.go(); - long stop = System.currentTimeMillis(); - printIfVerbose("That took " + (stop-start) + " milliseconds"); - if (!cpd.getMatches().hasNext()) { - printIfVerbose("No duplicates over " + minimumTokenCount + " tokens found"); - write("No problems found"); - } else { - printIfVerbose("Duplicates found; putting a report in " + outputFile); - write(new SimpleRenderer().render(cpd.getMatches())); - } - } catch(IOException ex){ - ex.printStackTrace(); - throw new BuildException("IOException in task", ex); - } - } + public void execute() throws BuildException { + try { + validateFields(); - private void write(String content) throws IOException { - Writer writer = getToFileWriter(project.getBaseDir().toString()); - writer.write(content); - writer.close(); + log("Tokenizing files", Project.MSG_INFO); + CPD cpd = new CPD(minimumTokenCount, new JavaLanguage()); + tokenizeFiles(cpd); + + log("Starting to analyze code", Project.MSG_INFO); + long timeTaken = analyzeCode(cpd); + log("Done analyzing code; that took " + timeTaken + " milliseconds"); + + log("Generating report", Project.MSG_INFO); + report(cpd); + } catch (IOException ioe) { + log(ioe.toString(), Project.MSG_ERR); + throw new BuildException("IOException during task execution", ioe); + } catch (ReportException re) { + log(re.toString(), Project.MSG_ERR); + throw new BuildException("ReportException during task execution", re); + } } - private Writer getToFileWriter(String baseDir) throws IOException { - String outFile = outputFile; - PathChecker pc = new PathChecker(System.getProperty("os.name")); - if (!pc.isAbsolute(outputFile)) { - outFile = baseDir + System.getProperty("file.separator") + outputFile; + private void report(CPD cpd) throws ReportException { + if (!cpd.getMatches().hasNext()) { + log("No duplicates over " + minimumTokenCount + " tokens found", Project.MSG_INFO); + } + Renderer renderer = createRenderer(); + if (outputFile.isAbsolute()) { + new FileReporter(outputFile).report(renderer.render(cpd.getMatches())); + } else { + new FileReporter(new File(project.getBaseDir(), outputFile.toString())); + } + } + + + private void tokenizeFiles(CPD cpd) throws IOException { + for (Iterator iterator = filesets.iterator(); iterator.hasNext();) { + FileSet fileSet = (FileSet) iterator.next(); + DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(project); + String[] includedFiles = directoryScanner.getIncludedFiles(); + for (int i = 0; i < includedFiles.length; i++) { + File file = new File(directoryScanner.getBasedir() + System.getProperty("file.separator") + includedFiles[i]); + log("Tokenizing " + file.getAbsolutePath(), Project.MSG_VERBOSE); + cpd.add(file); } - return new BufferedWriter(new FileWriter(new File(outFile))); + } + } + + private long analyzeCode(CPD cpd) { + long start = System.currentTimeMillis(); + cpd.go(); + long stop = System.currentTimeMillis(); + return stop - start; + } + + private Renderer createRenderer() { + if (format.equals(TEXT_FORMAT)) { + return new SimpleRenderer(); + } else + return new XMLRenderer(); } private void validateFields() throws BuildException{ @@ -114,16 +124,19 @@ public class CPDTask extends Task { this.minimumTokenCount = minimumTokenCount; } - public void setOutputFile(String outputFile) { + public void setOutputFile(File outputFile) { this.outputFile = outputFile; } - public void setVerbose(boolean verbose) { - this.verbose = verbose; + public void setFormat(FormatAttribute formatAttribute) { + format = formatAttribute.getValue(); } - private void printIfVerbose(String in) { - if (verbose) - System.out.println(in); + public static class FormatAttribute extends EnumeratedAttribute { + private String[] formats = new String[] {XML_FORMAT, TEXT_FORMAT}; + + public String[] getValues() { + return formats; + } } } diff --git a/pmd/src/net/sourceforge/pmd/cpd/CPPLanguage.java b/pmd/src/net/sourceforge/pmd/cpd/CPPLanguage.java index bddec941d2..a87f01618a 100644 --- a/pmd/src/net/sourceforge/pmd/cpd/CPPLanguage.java +++ b/pmd/src/net/sourceforge/pmd/cpd/CPPLanguage.java @@ -1,7 +1,7 @@ package net.sourceforge.pmd.cpd; -import java.io.FilenameFilter; import java.io.File; +import java.io.FilenameFilter; public class CPPLanguage implements Language{ diff --git a/pmd/src/net/sourceforge/pmd/cpd/CPPTokenizer.java b/pmd/src/net/sourceforge/pmd/cpd/CPPTokenizer.java index 0676501093..c1abd56bd9 100644 --- a/pmd/src/net/sourceforge/pmd/cpd/CPPTokenizer.java +++ b/pmd/src/net/sourceforge/pmd/cpd/CPPTokenizer.java @@ -1,16 +1,16 @@ package net.sourceforge.pmd.cpd; -import net.sourceforge.pmd.cpd.cppast.TokenMgrError; +import net.sourceforge.pmd.cpd.cppast.CPPParser; import net.sourceforge.pmd.cpd.cppast.CPPParserTokenManager; import net.sourceforge.pmd.cpd.cppast.Token; -import net.sourceforge.pmd.cpd.cppast.CPPParser; +import net.sourceforge.pmd.cpd.cppast.TokenMgrError; -import java.io.Reader; import java.io.IOException; import java.io.LineNumberReader; +import java.io.Reader; import java.io.StringReader; -import java.util.List; import java.util.ArrayList; +import java.util.List; public class CPPTokenizer implements Tokenizer { protected String EOL = System.getProperty("line.separator", "\n"); diff --git a/pmd/src/net/sourceforge/pmd/cpd/FileReporter.java b/pmd/src/net/sourceforge/pmd/cpd/FileReporter.java new file mode 100644 index 0000000000..90c15232d0 --- /dev/null +++ b/pmd/src/net/sourceforge/pmd/cpd/FileReporter.java @@ -0,0 +1,34 @@ +package net.sourceforge.pmd.cpd; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; + +/** + * @author Philippe T'Seyen + */ +public class FileReporter +{ + private File reportFile; + + public FileReporter(File reportFile) { + if (reportFile == null) throw new NullPointerException("reportFile can not be null"); + this.reportFile = reportFile; + } + + public void report(String content) throws ReportException { + try { + Writer writer = null; + try { + writer = new BufferedWriter(new FileWriter(reportFile)); + writer.write(content); + } finally { + if (writer != null) writer.close(); + } + } catch (IOException ioe) { + throw new ReportException(ioe); + } + } +} diff --git a/pmd/src/net/sourceforge/pmd/cpd/JavaLanguage.java b/pmd/src/net/sourceforge/pmd/cpd/JavaLanguage.java index 1424c1a1c4..197c507191 100644 --- a/pmd/src/net/sourceforge/pmd/cpd/JavaLanguage.java +++ b/pmd/src/net/sourceforge/pmd/cpd/JavaLanguage.java @@ -1,7 +1,7 @@ package net.sourceforge.pmd.cpd; -import java.io.FilenameFilter; import java.io.File; +import java.io.FilenameFilter; public class JavaLanguage implements Language { diff --git a/pmd/src/net/sourceforge/pmd/cpd/ReportException.java b/pmd/src/net/sourceforge/pmd/cpd/ReportException.java new file mode 100644 index 0000000000..fc02765758 --- /dev/null +++ b/pmd/src/net/sourceforge/pmd/cpd/ReportException.java @@ -0,0 +1,11 @@ +package net.sourceforge.pmd.cpd; + +/** + * @author Philippe T'Seyen + */ +public class ReportException extends Exception +{ + public ReportException(Throwable cause) { + super(cause); + } +} diff --git a/pmd/xdocs/credits.xml b/pmd/xdocs/credits.xml index 9e9f7eaa6c..d9501eb259 100644 --- a/pmd/xdocs/credits.xml +++ b/pmd/xdocs/credits.xml @@ -10,11 +10,11 @@
    +
  • Philippe T'Seyen - refactoring and cleanup of the CPD Ant task, an XML renderer (with unit tests!) for CPD
  • Michael Montuori - bug reports on the Gel IDE plugin
  • Michael Hosier - bug reports on the Gel IDE plugin
  • Ian Shef - bug reports on the Gel IDE plugin
  • Matthew Harrah - script bug report
  • -
  • Philippe T'Seyen - an XML renderer (with unit tests!) for CPD
  • Richard Jenson - CPD on Win32 troubleshooting
  • Daniel Bruguier - CPD on Win32 troubleshooting
  • Mario Claerhout - CPD optimizations and suggestions