diff options
author | Jean Michel-Lemieux | 2002-04-01 19:43:06 +0000 |
---|---|---|
committer | Jean Michel-Lemieux | 2002-04-01 19:43:06 +0000 |
commit | 7ac42b17cc92560dbb827e1e90a2c11401dd233c (patch) | |
tree | c220d47209e3637afade74211f6adcf423f108de /tests | |
parent | db341482a588d4f51558f056ada607d040ab05d9 (diff) | |
download | eclipse.platform.team-7ac42b17cc92560dbb827e1e90a2c11401dd233c.tar.gz eclipse.platform.team-7ac42b17cc92560dbb827e1e90a2c11401dd233c.tar.xz eclipse.platform.team-7ac42b17cc92560dbb827e1e90a2c11401dd233c.zip |
- Changes due CVSTeamProvider.update() signature change
- Log formatter support for CSV output and confidence intervals
- Log formatter UI frontend
- Head to head benchmark test Command line vs. Eclipse.
Diffstat (limited to 'tests')
27 files changed, 1117 insertions, 308 deletions
diff --git a/tests/org.eclipse.team.tests.cvs.core/benchmark/readme.txt b/tests/org.eclipse.team.tests.cvs.core/benchmark/readme.txt index 7dba4913d..6f64e0e00 100644 --- a/tests/org.eclipse.team.tests.cvs.core/benchmark/readme.txt +++ b/tests/org.eclipse.team.tests.cvs.core/benchmark/readme.txt @@ -102,29 +102,21 @@ Inspecting the Output 3. Run any of the following Java programs: - org.eclipse.team.tests.ccvs.ui.logformatter.PrintAverageMain + org.eclipse.team.tests.ccvs.ui.logformatter.PrintSummaryMain ------------------------------------------------------------ Synopsis: - Prints the average of the output of all runs contained in a particular + Prints a summary of the output of all runs contained in a particular XML log file. It is not possible to average runs in multiple log files at once without merging the files together on disk. [Strip the closing tag of the first file, and the opening tag of the second file, then append the second file to the first] Program arguments: - <log> : the path of the log file to print - - - org.eclipse.team.tests.ccvs.ui.logformatter.PrintRawMain - -------------------------------------------------------- - - Synopsis: - Prints the raw output of each individual run contained in a particular - XML log file without summarizing the data in any way. - - Program arguments: - <log> : the path of the log file to print + <log> : the path of the log file to print + -out <file> : specify an output file, otherwise sends to stdout + -csv : writes the data in comma separated values format + -raw : prints a raw dump without collating or averaging results org.eclipse.team.tests.ccvs.ui.logformatter.PrintDiffMain @@ -139,10 +131,20 @@ Inspecting the Output Program arguments: <newer log> : the path of the "newer" log file <older log> : the path of the "older" log file - -t <thresh> : specify the minimum non-negligible absolute difference in ms + -out <file> : specify an output file, otherwise sends to stdout + -csv : writes the data in comma separated values format + -t <thresh> : specify the minimum non-negligible absolute % change -i : ignore negligible changes in results [filter them out] + org.eclipse.team.tests.ccvs.ui.logformatter.LogFormatterUIMain + --------------------------------------------------------- + + Synopsis: + Provides a GUI frontend to the log formatting tools. To run this, + you must ensure that the SWT DLL is on the java library path. + + What is Being Logged ==================== diff --git a/tests/org.eclipse.team.tests.cvs.core/plugin.xml b/tests/org.eclipse.team.tests.cvs.core/plugin.xml index 8ba42053e..e7bd35bd2 100644 --- a/tests/org.eclipse.team.tests.cvs.core/plugin.xml +++ b/tests/org.eclipse.team.tests.cvs.core/plugin.xml @@ -82,6 +82,12 @@ class="org.eclipse.team.tests.ccvs.ui.benchmark.WorkflowTests"> </run> </test> + <test + id="cvsui.benchmark.command"> + <run + class="org.eclipse.team.tests.ccvs.ui.benchmark.CommandTests"> + </run> + </test> </extension> <extension point="org.eclipse.ui.perspectives"> diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/CVSTestSetup.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/CVSTestSetup.java index 153f9f77a..7488c9150 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/CVSTestSetup.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/CVSTestSetup.java @@ -38,7 +38,7 @@ public class CVSTestSetup extends TestSetup { } public static void loadProperties() { - String propertiesFile = "e:/repository.properties"; + String propertiesFile = System.getProperty("eclipse.cvs.properties"); if (propertiesFile == null) return; File file = new File(propertiesFile); if (file.isDirectory()) file = new File(file, "repository.properties"); diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/EclipseTest.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/EclipseTest.java index 5df35d0f3..4aec06d22 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/EclipseTest.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/EclipseTest.java @@ -160,7 +160,7 @@ public class EclipseTest extends EclipseWorkspaceTest { if(ignoreLocalChanges) { options = new LocalOption[] {Update.IGNORE_LOCAL_CHANGES}; } - getProvider(container).update(resources, options, null, null, DEFAULT_MONITOR); + getProvider(container).update(resources, options, null, true /*createBackups*/, DEFAULT_MONITOR); return resources; } @@ -169,7 +169,7 @@ public class EclipseTest extends EclipseWorkspaceTest { if(ignoreLocalChanges) { options = new LocalOption[] {Update.IGNORE_LOCAL_CHANGES}; } - getProvider(project).update(new IResource[] {project}, options, tag, null, DEFAULT_MONITOR); + getProvider(project).update(new IResource[] {project}, options, tag, true /*createBackups*/, DEFAULT_MONITOR); } public void commitProject(IProject project) throws TeamException { diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/CVSProviderTest.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/CVSProviderTest.java index 390f9fe04..b62fdbf4e 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/CVSProviderTest.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/CVSProviderTest.java @@ -131,7 +131,7 @@ public class CVSProviderTest extends EclipseTest { // Commit the copy and update the project getProvider(copy).checkin(new IResource[] {copy}, IResource.DEPTH_INFINITE, DEFAULT_MONITOR); - getProvider(project).update(new IResource[] {project}, Command.NO_LOCAL_OPTIONS, null, null, DEFAULT_MONITOR); + getProvider(project).update(new IResource[] {project}, Command.NO_LOCAL_OPTIONS, null, true /*createBackups*/, DEFAULT_MONITOR); assertEquals(project, copy); } diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/SyncElementTest.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/SyncElementTest.java index e2976ef03..a1c90b2e3 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/SyncElementTest.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/core/provider/SyncElementTest.java @@ -304,8 +304,8 @@ public class SyncElementTest extends EclipseTest { // Catch up to the file1.txt conflict using UPDATE with ignoreLocalChanges getProvider(project).update(new IResource[] {project.getFile("file1.txt")}, - new Command.LocalOption[] {Update.IGNORE_LOCAL_CHANGES, Command.DO_NOT_RECURSE}, - null, null, DEFAULT_MONITOR); + new Command.LocalOption[] {Update.IGNORE_LOCAL_CHANGES, Command.DO_NOT_RECURSE}, + null, true /*createBackups*/, DEFAULT_MONITOR); tree = CVSWorkspaceRoot.getRemoteSyncTree(project, CVSTag.DEFAULT, DEFAULT_MONITOR); assertSyncEquals("testFileConflict", tree, new String[] { "file1.txt", "folder1/", "folder1/a.txt"}, @@ -399,8 +399,8 @@ public class SyncElementTest extends EclipseTest { file = project.getFile("add2a.txt"); file.delete(false, DEFAULT_MONITOR); getProvider(project).update(new IResource[] {project.getFile("add1a.txt"), project.getFile("add2a.txt")}, - new Command.LocalOption[] {Command.DO_NOT_RECURSE}, - null, null, DEFAULT_MONITOR); + new Command.LocalOption[] {Command.DO_NOT_RECURSE}, + null, true /*createBackups*/, DEFAULT_MONITOR); tree = CVSWorkspaceRoot.getRemoteSyncTree(project, CVSTag.DEFAULT, DEFAULT_MONITOR); assertSyncEquals("testAdditionConflicts", tree, new String[] { "add1a.txt", "add2a.txt"}, @@ -661,7 +661,7 @@ public class SyncElementTest extends EclipseTest { // Catch up to the addition by updating getProvider(project).update(new IResource[] {element.getLocal()}, new Command.LocalOption[] {Command.DO_NOT_RECURSE}, - null, null, DEFAULT_MONITOR); + null, true /*createBackups*/, DEFAULT_MONITOR); // Get the sync tree again for the project and ensure the added resource is in sync tree = CVSWorkspaceRoot.getRemoteSyncTree(project, CVSTag.DEFAULT, DEFAULT_MONITOR); @@ -739,7 +739,8 @@ public class SyncElementTest extends EclipseTest { tagProject(project, new CVSTag("v1", CVSTag.VERSION)); tagProject(project, new CVSTag("branch1", CVSTag.BRANCH)); - getProvider(copy).update(new IResource[] {copy}, Command.NO_LOCAL_OPTIONS, new CVSTag("branch1", CVSTag.BRANCH), null, DEFAULT_MONITOR); + getProvider(copy).update(new IResource[] {copy}, Command.NO_LOCAL_OPTIONS, + new CVSTag("branch1", CVSTag.BRANCH), true /*createBackups*/, DEFAULT_MONITOR); // make changes on the branch addResources(copy, new String[] {"addition.txt", "folderAddition/", "folderAddition/new.txt"}, true); @@ -773,7 +774,7 @@ public class SyncElementTest extends EclipseTest { IProject project = createProject("testSyncOnBranch", new String[] { "file1.txt", "file2.txt", "file3.txt", "folder1/", "folder1/a.txt", "folder1/b.txt"}); CVSTag branch = new CVSTag("branch1", CVSTag.BRANCH); tagProject(project, branch); - getProvider(project).update(new IResource[] {project}, Command.NO_LOCAL_OPTIONS, branch, null, DEFAULT_MONITOR); + getProvider(project).update(new IResource[] {project}, Command.NO_LOCAL_OPTIONS, branch, true /*createBackups*/, DEFAULT_MONITOR); // Checkout and modify a copy IProject copy = checkoutCopy(project, branch); diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/CVSUITestCase.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/CVSUITestCase.java index 05c0c1916..c1b7004eb 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/CVSUITestCase.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/CVSUITestCase.java @@ -22,6 +22,7 @@ import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceDescription; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.action.Action; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.viewers.StructuredSelection; @@ -31,6 +32,7 @@ import org.eclipse.team.ccvs.core.CVSProviderPlugin; import org.eclipse.team.ccvs.core.CVSTag; import org.eclipse.team.ccvs.core.ICVSRemoteFolder; import org.eclipse.team.core.RepositoryProvider; +import org.eclipse.team.internal.ccvs.core.client.listeners.IConsoleListener; import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation; import org.eclipse.team.internal.ccvs.ui.CVSUIPlugin; import org.eclipse.team.internal.ccvs.ui.RepositoryManager; @@ -91,6 +93,9 @@ public class CVSUITestCase extends LoggingTestCase { description.setAutoBuilding(false); workspace.setDescription(description); + // disable CVS console + CVSProviderPlugin.getPlugin().setConsoleListener(null); + // wait for UI to settle Util.processEventsUntil(100); } @@ -135,7 +140,12 @@ public class CVSUITestCase extends LoggingTestCase { */ protected void actionCheckoutProjects(String[] projectNames, CVSTag[] tags) throws Exception { ICVSRemoteFolder[] projects = lookupRemoteProjects(projectNames, tags); - runActionDelegate(new AddToWorkspaceAction(), projects, "Repository View Checkout action"); + AddToWorkspaceAction action = new AddToWorkspaceAction() { + protected int confirmOverwrite(IProject project) { + return 2; // yes to all + } + }; + runActionDelegate(action, projects, "Repository View Checkout action"); timestampGranularityHiatus(); } @@ -293,16 +303,17 @@ public class CVSUITestCase extends LoggingTestCase { * Gets an instance of the Synchronize view */ protected SyncView getSyncView() { - // based on org.eclipse.team.internal.ccvs.ui.wizards.SharingWizard - try { - CVSUIPlugin.getActivePage().showView(SyncView.VIEW_ID); - } catch (PartInitException e) { - CVSUIPlugin.log(e.getStatus()); - } - SyncView view = (SyncView) CVSUIPlugin.getActivePage().findView(SyncView.VIEW_ID); + SyncView view = (SyncView)CVSUIPlugin.getActivePage().findView(SyncView.VIEW_ID); if (view == null) { view = SyncView.findInActivePerspective(); } + if (view != null) { + try { + CVSUIPlugin.getActivePage().showView(SyncView.VIEW_ID); + } catch (PartInitException e) { + CVSUIPlugin.log(e.getStatus()); + } + } assertNotNull("Could not obtain a Sync View.", view); return view; } diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/LoggingTestCase.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/LoggingTestCase.java index df23eea94..70effb4b9 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/LoggingTestCase.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/LoggingTestCase.java @@ -26,6 +26,11 @@ public class LoggingTestCase extends TestCase { * @param result the result object */ public void run(TestResult result) { + // run the garbage collector now to improve benchmark precision + for (int i = 0; i < 4; ++i) { + System.runFinalization(); + System.gc(); + } if (result instanceof LoggingTestResult) { logResult = (LoggingTestResult) result; disableLogStack = 0; diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/benchmark/AllTests.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/benchmark/AllTests.java index bbc867946..6a3fcb522 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/benchmark/AllTests.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/benchmark/AllTests.java @@ -13,6 +13,7 @@ public class AllTests extends TestSuite { TestSuite suite = new TestSuite(); suite.addTestSuite(SyncTests.class); suite.addTestSuite(WorkflowTests.class); + //suite.addTestSuite(CommandTests.class); return new BenchmarkTestSetup(suite); } diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/benchmark/CommandTests.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/benchmark/CommandTests.java new file mode 100644 index 000000000..4545e5c14 --- /dev/null +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/benchmark/CommandTests.java @@ -0,0 +1,90 @@ +package org.eclipse.team.tests.ccvs.ui.benchmark; + +/* + * (c) Copyright IBM Corp. 2000, 2001. + * All Rights Reserved. + */ + +import junit.framework.Protectable; +import junit.framework.Test; +import junit.framework.TestSuite; +import org.eclipse.core.resources.IContainer; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.Path; +import org.eclipse.team.ccvs.core.CVSTag; +import org.eclipse.team.internal.ccvs.core.client.Command; +import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot; +import org.eclipse.team.tests.ccvs.core.CommandLineCVSClient; +import org.eclipse.team.tests.ccvs.core.EclipseCVSClient; +import org.eclipse.team.tests.ccvs.ui.CVSUITestCase; +import org.eclipse.team.tests.ccvs.ui.Util; + +public class CommandTests extends CVSUITestCase { + private String baseName; + private IProject referenceProject; + private IProject eclipseProject; + private IProject uiProject; + + public CommandTests(String name) { + super(name); + } + public CommandTests() { + super(""); + } + public static Test suite() { + return new BenchmarkTestSetup(new TestSuite(CommandTests.class)); + } + + public void setUp() throws Exception { + super.setUp(); + baseName = Util.makeUniqueName(null, getName(), null); + referenceProject = Util.createProject(baseName + "-reference"); + eclipseProject = Util.createProject(baseName + "-eclipse"); + uiProject = Util.createProject(baseName); + } + + public void testCheckout() throws Throwable { + // import a large project + Util.importZipIntoProject(uiProject, BenchmarkTestSetup.BIG_ZIP_FILE); + disableLog(); + actionShareProject(uiProject); + syncCommitResources(new IResource[] { uiProject }, null, "initial"); + enableLog(); + Util.deleteProject(uiProject); + + // check it out using each client + startGroup("checkout big project"); + execute("co", Command.NO_ARGUMENTS, new String[] { "-P" }, new String[] { baseName }, "", new Protectable() { + public void protect() throws Throwable { + actionCheckoutProjects(new String[] { baseName }, new CVSTag[] { CVSTag.DEFAULT }); + } + }); + endGroup(); + } + + protected void execute(String command, String[] globalOptions, String[] localOptions, + String[] arguments, String pathRelativeToRoot, Protectable uiCode) throws Throwable { + startGroup("command line client"); + IContainer container = referenceProject; + if (pathRelativeToRoot.length() != 0) container = container.getFolder(new Path(pathRelativeToRoot)); + startTask(command); + CommandLineCVSClient.execute(testRepository.getLocation(), container.getLocation().toFile(), + command, globalOptions, localOptions, arguments); + endTask(); + endGroup(); + + startGroup("eclipse client"); + container = eclipseProject; + if (pathRelativeToRoot.length() != 0) container = container.getFolder(new Path(pathRelativeToRoot)); + startTask(command); + EclipseCVSClient.execute(testRepository, CVSWorkspaceRoot.getCVSFolderFor(container), + command, globalOptions, localOptions, arguments); + endTask(); + endGroup(); + + startGroup("user interface"); + uiCode.protect(); + endGroup(); + } +} diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/ArgumentParser.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/ArgumentParser.java new file mode 100644 index 000000000..ee9359101 --- /dev/null +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/ArgumentParser.java @@ -0,0 +1,43 @@ +package org.eclipse.team.tests.ccvs.ui.logformatter; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +public class ArgumentParser { + protected ArgumentParser() { + } + + public boolean parse(String[] args) { + int index = 0; + String option = null; + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if (arg == null) continue; + if (arg.charAt(0) == '-') { + if (option != null && ! handleOption(option, null)) return false; + option = arg; + } else if (option != null) { + if (! handleOption(option, arg)) return false; + option = null; + } else { + if (! handleArgument(index++, arg)) return false; + } + } + if (option != null && ! handleOption(option, null)) return false; + return handleFinished(); + } + + protected boolean handleFinished() { + return true; + } + + protected boolean handleArgument(int index, String arg) { + return false; + } + + protected boolean handleOption(String option, String arg) { + return false; + } +} diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/DelimitedValuesWriter.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/DelimitedValuesWriter.java new file mode 100644 index 000000000..95be9e392 --- /dev/null +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/DelimitedValuesWriter.java @@ -0,0 +1,48 @@ +package org.eclipse.team.tests.ccvs.ui.logformatter; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import java.io.PrintStream; + +public class DelimitedValuesWriter { + private static final String BEGIN_QUOTE = "\""; + private static final String END_QUOTE = "\""; + private PrintStream ps; + private String delimiter; + private boolean quoted; + private boolean firstField; + + public DelimitedValuesWriter(PrintStream ps, String delimiter, boolean quoted) { + this.ps = ps; + this.delimiter = delimiter; + this.quoted = quoted; + this.firstField = true; + } + + public void printField(String field) { + if (firstField) { + firstField = false; + } else { + ps.print(delimiter); + } + if (quoted) ps.print(BEGIN_QUOTE); + ps.print(field); + if (quoted) ps.print(END_QUOTE); + } + public void printFields(String[] fields) { + for (int i = 0; i < fields.length; i++) { + printField(fields[i]); + } + } + public void printRecord(String[] fields) { + printFields(fields); + endRecord(); + } + public void endRecord() { + ps.println(); + firstField = true; + } +} diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/LogEntry.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/LogEntry.java index 353fbe605..e3300a2d8 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/LogEntry.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/LogEntry.java @@ -8,10 +8,6 @@ package org.eclipse.team.tests.ccvs.ui.logformatter; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import javax.xml.parsers.SAXParserFactory; import junit.framework.Assert; import org.xml.sax.Attributes; @@ -96,7 +92,7 @@ public abstract class LogEntry { } else if ("result".equals(localName)) { Assert.assertNotNull(current); Assert.assertTrue(current instanceof TaskEntry); - ((TaskEntry) current).addResult(attributes); + ((TaskEntry) current).addResult(new Result(attributes)); } else if ("abort".equals(localName)) { // currently we ignore failure entries // XXX need a good way to represent failures diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/LogFormatterUIMain.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/LogFormatterUIMain.java new file mode 100644 index 000000000..14e6b3a61 --- /dev/null +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/LogFormatterUIMain.java @@ -0,0 +1,182 @@ +package org.eclipse.team.tests.ccvs.ui.logformatter; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TabFolder; +import org.eclipse.swt.widgets.TabItem; +import org.eclipse.swt.widgets.Text; + +/** + * Quick and dirty UI frontend for the log formatters. + */ +public class LogFormatterUIMain { + + public LogFormatterUIMain() { + } + + public static void main(String[] args) { + new LogFormatterUIMain().run(); + } + + public void run() { + Display display = new Display(); + Shell shell = new Shell(display); + + shell.setText("Log Formatter UI"); + createContents(shell); + + shell.setSize(500, 300); + shell.open(); + while (! shell.isDisposed()) { + if (! display.readAndDispatch()) display.sleep(); + } + shell.dispose(); + display.dispose(); + } + + protected void createContents(Composite parent) { + parent.setLayout(new FillLayout()); + TabFolder tabFolder = new TabFolder(parent, SWT.NONE); + createSummaryTabContents(new TabItem(tabFolder, SWT.NONE)); + createDiffTabContents(new TabItem(tabFolder, SWT.NONE)); + } + + protected void createSummaryTabContents(TabItem item) { + Composite top = new Composite(item.getParent(), SWT.NONE); + item.setControl(top); + item.setText("Create Log Summary"); + GridLayout layout = new GridLayout(); + layout.numColumns = 3; + top.setLayout(layout); + + final Text logFileText = createFileSelector(top, "Log file path: "); + final Text outputFileText = createFileSelector(top, "Output file path: "); + + final Button csvCheckButton = new Button(top, SWT.CHECK); + csvCheckButton.setText("Produce comma separated values data"); + GridData data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_CENTER); + data.horizontalSpan = 3; + csvCheckButton.setLayoutData(data); + + final Button rawCheckButton = new Button(top, SWT.CHECK); + rawCheckButton.setText("Do not merge results from successive iterations"); + data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_CENTER); + data.horizontalSpan = 3; + rawCheckButton.setLayoutData(data); + + createRunButton(top, new Runnable() { + public void run() { + PrintSummaryMain.main(new String[] { + logFileText.getText(), + "-out", outputFileText.getText(), + csvCheckButton.getSelection() ? "-csv" : null, + rawCheckButton.getSelection() ? "-raw" : null }); + } + }); + } + + protected void createDiffTabContents(TabItem item) { + Composite top = new Composite(item.getParent(), SWT.NONE); + item.setControl(top); + item.setText("Create Log Diff"); + GridLayout layout = new GridLayout(); + layout.numColumns = 3; + top.setLayout(layout); + + final Text newerLogFileText = createFileSelector(top, "Newer log file path: "); + final Text olderLogFileText = createFileSelector(top, "Older log file path: "); + final Text outputFileText = createFileSelector(top, "Output file path: "); + + Label label = new Label(top, SWT.NONE); + label.setText("Threshold %"); + label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER)); + + final Text thresholdText = new Text(top, SWT.BORDER); + thresholdText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_CENTER)); + thresholdText.setText("0"); + + new Label(top, SWT.NONE); + + final Button csvCheckButton = new Button(top, SWT.CHECK); + csvCheckButton.setText("Produce comma separated values data"); + GridData data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_CENTER); + data.horizontalSpan = 3; + csvCheckButton.setLayoutData(data); + + final Button ignoreCheckButton = new Button(top, SWT.CHECK); + ignoreCheckButton.setText("Ignore negligible changes in results"); + data = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_CENTER); + data.horizontalSpan = 3; + ignoreCheckButton.setLayoutData(data); + + createRunButton(top, new Runnable() { + public void run() { + PrintDiffMain.main(new String[] { + newerLogFileText.getText(), + olderLogFileText.getText(), + "-out", outputFileText.getText(), + "-t", thresholdText.getText(), + csvCheckButton.getSelection() ? "-csv" : null, + ignoreCheckButton.getSelection() ? "-i" : null }); + } + }); + } + + protected Text createFileSelector(Composite parent, String labelText) { + Label label = new Label(parent, SWT.NONE); + label.setText(labelText); + label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER)); + + final Text text = new Text(parent, SWT.BORDER); + text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_CENTER)); + + Button browseButton = new Button(parent, SWT.PUSH); + browseButton.setText("Browse..."); + browseButton.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + FileDialog dialog = new FileDialog(text.getShell(), SWT.OPEN); + dialog.setFileName(text.getText()); + String name = dialog.open(); + if (name != null) { + text.setText(name); + } + } + }); + browseButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL)); + return text; + } + + protected Button createRunButton(Composite parent, final Runnable runnable) { + Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); + GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_END | GridData.GRAB_VERTICAL); + data.horizontalSpan = 3; + separator.setLayoutData(data); + + final Button runButton = new Button(parent, SWT.PUSH); + runButton.setText("Run"); + data = new GridData(GridData.HORIZONTAL_ALIGN_END | GridData.VERTICAL_ALIGN_FILL); + data.horizontalSpan = 3; + runButton.setLayoutData(data); + runButton.addListener(SWT.Selection, new Listener() { + public void handleEvent(Event event) { + runButton.getDisplay().asyncExec(runnable); + } + }); + return runButton; + } +} diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/MergeRunsVisitor.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/MergeRunsVisitor.java index c500cd9e4..86e12e994 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/MergeRunsVisitor.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/MergeRunsVisitor.java @@ -62,6 +62,9 @@ public class MergeRunsVisitor implements ILogEntryVisitor { if (newEntry == null) { newEntry = new TaskEntry(parent, entry.getName()); } - newEntry.addRuns(entry.getTotalMillis(), entry.getTotalRuns()); + Result[] results = entry.getResults(); + for (int i = 0; i < results.length; i++) { + newEntry.addResult(results[i]); + } } } diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintAverageMain.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintAverageMain.java deleted file mode 100644 index fb5956483..000000000 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintAverageMain.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.eclipse.team.tests.ccvs.ui.logformatter; - -/* - * (c) Copyright IBM Corp. 2000, 2002. - * All Rights Reserved. - */ - -import java.io.File; -import java.io.PrintStream; - -public class PrintAverageMain { - public static void main(String[] args) { - if (args.length != 1) { - System.err.println("Usage: java PrintAverageMain <log>"); - return; - } - File file = new File(args[0]); - try { - // read and merge the log - RootEntry root = LogEntry.readLog(file); - MergeRunsVisitor mergeVisitor = new MergeRunsVisitor(null); - root.accept(mergeVisitor); - root = mergeVisitor.getMergedRoot(); - - // print header - PrintStream ps = System.out; - ps.println("=== AVERAGED TEST LOG SUMMARY ==="); - ps.println("File: " + file); - ps.println(" Generated: " + root.getTimestamp()); - ps.println(" SDK Build: " + root.getSDKBuildId()); - ps.println(); - - // print the log summary - root.accept(new PrintSummaryVisitor(ps)); - } catch (Exception e) { - System.err.println("An error occurred while parsing: " + file); - e.printStackTrace(); - return; - } - } -} diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintCSVDiffVisitor.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintCSVDiffVisitor.java new file mode 100644 index 000000000..54dfb1356 --- /dev/null +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintCSVDiffVisitor.java @@ -0,0 +1,94 @@ +package org.eclipse.team.tests.ccvs.ui.logformatter; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +public class PrintCSVDiffVisitor extends PrintDiffVisitor { + private static final String GROUP_DELIMITER = " / "; + private DelimitedValuesWriter writer; + private String caseName; + private String groupName; + + /** + * Creates a diff visitor that generates CSV output. + * + * @param writer the delimited values writer + * @see PrintDiffVisitor + */ + public PrintCSVDiffVisitor(DelimitedValuesWriter writer, RootEntry olderRoot, int threshold, boolean ignoreNegligible) { + super(olderRoot, threshold, ignoreNegligible); + this.writer = writer; + } + + protected void visitRootEntry(RootEntry entry, RootEntry olderEntry) { + entry.acceptChildren(this); + } + + protected void visitCaseEntry(CaseEntry entry, CaseEntry olderEntry) { + caseName = entry.getName(); + groupName = null; + entry.acceptChildren(this); + } + + protected void visitGroupEntry(GroupEntry entry, GroupEntry olderEntry) { + String oldGroupName = groupName; + if (groupName == null) { + groupName = entry.getName(); + } else { + groupName += GROUP_DELIMITER + entry.getName(); + } + entry.acceptChildren(this); + groupName = oldGroupName; + } + + protected void visitTaskEntry(TaskEntry entry, TaskEntry olderEntry) { + writer.printFields(new String[] { + caseName, // case + groupName, // group + entry.getName() // task + }); + printTaskEntry(entry); + printTaskEntry(olderEntry); + if (entry.getTotalRuns() != 0 && olderEntry.getTotalRuns() != 0) { + int olderMean = olderEntry.getAverageMillis(); + int diff = entry.getAverageMillis() - olderMean; + if (isNegligible(entry, olderEntry)) { + writer.printField("NEGLIGIBLE"); + } else { + writer.printField(diff > 0 ? "SLOWER" : "FASTER"); // change type + } + writer.printField(Integer.toString(Math.abs(diff))); // change + if (olderMean != 0) { + writer.printField(Util.formatPercentageRatio(Math.abs(diff), olderMean)); // % change + } else { + writer.printField(""); + } + } else { + writer.printFields(new String[] { "", "", "" }); + } + writer.endRecord(); + } + + protected void printTaskEntry(TaskEntry entry) { + if (entry.getTotalRuns() != 0) { + int mean = entry.getAverageMillis(); + writer.printFields(new String[] { + Integer.toString(entry.getTotalRuns()), // runs + Integer.toString(mean) // average + }); + if (entry.getTotalRuns() > 1 && mean != 0) { + int confidence = entry.getConfidenceInterval(); + writer.printFields(new String[] { + Integer.toString(confidence), // 95% confidence interval + Util.formatPercentageRatio(confidence, mean) // 95% c.i. as a percentage + }); + } else { + writer.printFields(new String[] { "", "" }); + } + } else { + writer.printFields(new String[] { "0", "", "", "" }); + } + } +} diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintCSVSummaryVisitor.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintCSVSummaryVisitor.java new file mode 100644 index 000000000..2ebf7cd7c --- /dev/null +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintCSVSummaryVisitor.java @@ -0,0 +1,76 @@ +package org.eclipse.team.tests.ccvs.ui.logformatter; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +public class PrintCSVSummaryVisitor implements ILogEntryVisitor { + private static final String GROUP_DELIMITER = " / "; + private DelimitedValuesWriter writer; + private String caseName; + private String groupName; + + /** + * Creates a visitor to print a log as comma-separated values. + * @param writer the delimited values writer + */ + public PrintCSVSummaryVisitor(DelimitedValuesWriter writer) { + this.writer = writer; + } + + public void visitRootEntry(RootEntry entry) { + entry.acceptChildren(this); + } + + public void visitCaseEntry(CaseEntry entry) { + caseName = entry.getName(); + groupName = null; + entry.acceptChildren(this); + } + + public void visitGroupEntry(GroupEntry entry) { + String oldGroupName = groupName; + if (groupName == null) { + groupName = entry.getName(); + } else { + groupName += GROUP_DELIMITER + entry.getName(); + } + entry.acceptChildren(this); + groupName = oldGroupName; + } + + public void visitTaskEntry(TaskEntry entry) { + writer.printFields(new String[] { + caseName, // case + groupName, // group + entry.getName() // task + }); + if (entry.getTotalRuns() != 0) { + int mean = entry.getAverageMillis(); + writer.printFields(new String[] { + Integer.toString(entry.getTotalRuns()), // runs + Integer.toString(mean) // average + }); + if (entry.getTotalRuns() > 1 && mean != 0) { + int confidence = entry.getConfidenceInterval(); + writer.printFields(new String[] { + Integer.toString(confidence), // 95% confidence interval + Util.formatPercentageRatio(confidence, mean) // 95% c.i. as a percentage + }); + } else { + writer.printFields(new String[] { "", "" }); + } + } else { + writer.printFields(new String[] { "0", "", "", "" }); + } + // append the result fields (ms) + Result[] results = entry.getResults(); + for (int i = 0; i < results.length; i++) { + Result result = results[i]; + if (result.getRuns() == 0) continue; + writer.printField(Integer.toString(result.getMillis() / result.getRuns())); + } + writer.endRecord(); + } +} diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintDiffMain.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintDiffMain.java index 40120c550..7a82f7a81 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintDiffMain.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintDiffMain.java @@ -5,65 +5,144 @@ package org.eclipse.team.tests.ccvs.ui.logformatter; * All Rights Reserved. */ +import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; import java.io.PrintStream; +import org.xml.sax.SAXException; + public class PrintDiffMain { public static void main(String[] args) { - File newerFile, olderFile; - int thresh = 1; - boolean ignore = false; + Parser parser = new Parser(); + if (! parser.parse(args)) { + System.err.println("Usage: <newer log> <older log> [-out <file>] [-csv] [-t <thresh>] [-i]"); + System.err.println(" -out <file> : specify the output file, default is console"); + System.err.println(" -csv : produce comma separated values data"); + System.err.println(" -t <thresh> : minimum non-negligible absolute % change"); + System.err.println(" -i : ignore negligible changes in results"); + return; + } try { - // lazy argument parsing - newerFile = new File(args[args.length - 2]); - olderFile = new File(args[args.length - 1]); - for (int i = 0; i < args.length - 2; ++i) { - if ("-i".equals(args[i])) { - ignore = true; - } else if ("-t".equals(args[i]) && i < args.length - 3) { - thresh = Integer.parseInt(args[++i], 10); - } else throw new IllegalArgumentException(args[i]); + PrintStream ps = System.out; + try { + if (parser.outputFile != null) ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(parser.outputFile))); + printDiff(ps, parser.newerLogFile, parser.olderLogFile, parser.csv, parser.thresh, parser.ignore); + } finally { + if (ps != System.out) ps.close(); } } catch (Exception e) { - System.err.println("Usage: java PrintDiffMain [-t thresh] [-i] <newer log> <older log>"); - System.err.println(" -t thresh: minimum non-negligible absolute difference in ms"); - System.err.println(" -i : ignore negligible changes in results"); + System.err.println("An error occurred:"); + e.printStackTrace(); return; } - - try { - // read and merge newer log - RootEntry newerRoot = LogEntry.readLog(newerFile); - MergeRunsVisitor mergeVisitor = new MergeRunsVisitor(null); - newerRoot.accept(mergeVisitor); - newerRoot = mergeVisitor.getMergedRoot(); + } - // read and merge older log - RootEntry olderRoot = LogEntry.readLog(olderFile); - olderRoot.accept(mergeVisitor); - olderRoot = mergeVisitor.getMergedRoot(); + private static void printDiff(PrintStream ps, File newerLogFile, File olderLogFile, + boolean csv, int thresh, boolean ignore) throws IOException, SAXException { + // read and merge newer log + RootEntry newerRoot = LogEntry.readLog(newerLogFile); + MergeRunsVisitor mergeVisitor = new MergeRunsVisitor(null); + newerRoot.accept(mergeVisitor); + newerRoot = mergeVisitor.getMergedRoot(); + // read and merge older log + RootEntry olderRoot = LogEntry.readLog(olderLogFile); + olderRoot.accept(mergeVisitor); + olderRoot = mergeVisitor.getMergedRoot(); + + // format options + StringBuffer options = new StringBuffer(); + if (thresh != 0) { + options.append("-t "); + options.append(Integer.toString(thresh)); + options.append(" "); + } + if (ignore) options.append("-i "); + + // format log file + if (csv) { + DelimitedValuesWriter writer = new DelimitedValuesWriter(ps, ",", true /*quoted*/); // print header - PrintStream ps = System.out; - ps.println("=== TEST LOG DIFF ==="); - ps.println("Newer File: " + newerFile); + writer.printRecord(new String[] { "", "Newer", "Older" }); + writer.printRecord(new String[] { "Log File", newerLogFile.toString(), olderLogFile.toString() }); + writer.printRecord(new String[] { "Generated", newerRoot.getTimestamp(), olderRoot.getTimestamp() }); + writer.printRecord(new String[] { "SDK Build", newerRoot.getSDKBuildId(), olderRoot.getSDKBuildId() }); + writer.endRecord(); + writer.printRecord(new String[] { "Options", "'" + options.toString() }); + writer.endRecord(); + writer.printRecord(new String[] { "", "", "", + "Newer", "", "", "", + "Older", "", "", "", + "", "", "" }); + writer.printRecord(new String[] { "Case", "Group", "Task", + "Runs", "Avg. (ms)", "95% C.I. (ms)", "95% C.I. (%)", + "Runs", "Avg. (ms)", "95% C.I. (ms)", "95% C.I. (%)", + "Change", "Diff (ms)", "Diff (%)" }); + // print quoted CSV data + PrintCSVDiffVisitor diffVisitor = new PrintCSVDiffVisitor(writer, olderRoot, thresh, ignore); + newerRoot.accept(diffVisitor); + } else { + // print header + ps.println("=== LOG DIFF ==="); + ps.println("Newer File: " + newerLogFile); ps.println(" Generated: " + newerRoot.getTimestamp()); ps.println(" SDK Build: " + newerRoot.getSDKBuildId()); - ps.println("Older File: " + olderFile); + ps.println("Older File: " + olderLogFile); ps.println(" Generated: " + olderRoot.getTimestamp()); ps.println(" SDK Build: " + olderRoot.getSDKBuildId()); - ps.println("Options:"); - ps.println(" threshold = " + thresh + " ms"); - ps.println(" ignore negligible = " + ignore); + ps.println("Options: " + options.toString()); ps.println(); - // compute and print the differences - PrintDiffVisitor diffVisitor = new PrintDiffVisitor(ps, olderRoot, thresh, ignore); + PrintTextDiffVisitor diffVisitor = new PrintTextDiffVisitor(ps, olderRoot, thresh, ignore); newerRoot.accept(diffVisitor); - } catch (Exception e) { - System.err.println("An error occurred while parsing logs"); - e.printStackTrace(); - return; } - } + } + + private static class Parser extends ArgumentParser { + public File newerLogFile = null; + public File olderLogFile = null; + public File outputFile = null; + public boolean csv = false; + public int thresh = 0; + public boolean ignore = false; + + protected boolean handleFinished() { + return newerLogFile != null && olderLogFile != null; + } + protected boolean handleArgument(int index, String arg) { + if (index == 0) { + newerLogFile = new File(arg); + } else if (index == 1) { + olderLogFile = new File(arg); + } else { + return false; + } + return true; + } + protected boolean handleOption(String option, String arg) { + if ("-out".equals(option)) { + if (arg == null) return false; + outputFile = new File(arg); + } else if ("-csv".equals(option)) { + if (arg != null) return false; + csv = true; + } else if ("-t".equals(option)) { + if (arg == null) return false; + try { + thresh = Integer.parseInt(arg, 10); + } catch (NumberFormatException e) { + return false; + } + if (thresh < 0) return false; + } else if ("-i".equals(option)) { + if (arg != null) return false; + ignore = true; + } else { + return false; + } + return true; + } + } } diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintDiffVisitor.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintDiffVisitor.java index acc18cd43..61f2b18e1 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintDiffVisitor.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintDiffVisitor.java @@ -5,160 +5,70 @@ package org.eclipse.team.tests.ccvs.ui.logformatter; * All Rights Reserved. */ -import java.io.PrintStream; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; +public abstract class PrintDiffVisitor implements ILogEntryVisitor { + protected RootEntry olderRoot; + protected int threshold; // threshold for negligible changes + protected boolean ignoreNegligible; // if true, ignores negligible changes + protected LogEntryContainer olderParent; // corresponding parent in older root -public class PrintDiffVisitor implements ILogEntryVisitor { - private PrintStream os; - private RootEntry olderRoot; - private int threshold; // threshold for negligible changes - private boolean ignoreNegligible; // if true, ignores negligible changes - private LogEntryContainer olderParent; // corresponding parent in older root - private List diffText; // list of things to print - private String indent; - /** * Creates a visitor to print a summary of the changes between a log * and an older one. Optionally ignores differences within a certain threshold. * Does not print older entries for which there are no corresponding newer ones. * - * @param os the output stream * @param olderRoot the root of the older log - * @param threshold the smallest non-negligible difference + * @param threshold the minimum non-negligible % change * @param ignoreNegligible if true, does not display negligible changes */ - public PrintDiffVisitor(PrintStream os, RootEntry olderRoot, int threshold, boolean ignoreNegligible) { - this.os = os; + public PrintDiffVisitor(RootEntry olderRoot, int threshold, boolean ignoreNegligible) { this.olderRoot = olderRoot; this.olderParent = null; this.threshold = threshold; this.ignoreNegligible = ignoreNegligible; - this.diffText = null; - this.indent = ""; } - private void visitContainer(LogEntryContainer container) { - LogEntryContainer prevOlderParent = olderParent; - indent += " "; - if (olderParent != null) { - olderParent = (LogEntryContainer) olderParent.findMember( - container.getName(), container.getClass()); - } - container.acceptChildren(this); - indent = indent.substring(2); - olderParent = prevOlderParent; - } + protected abstract void visitRootEntry(RootEntry entry, RootEntry olderEntry); + protected abstract void visitCaseEntry(CaseEntry entry, CaseEntry olderEntry); + protected abstract void visitGroupEntry(GroupEntry entry, GroupEntry olderEntry); + protected abstract void visitTaskEntry(TaskEntry entry, TaskEntry olderEntry); - /** - * Prints the root entry information. - */ public void visitRootEntry(RootEntry entry) { olderParent = olderRoot; - entry.acceptChildren(this); + visitRootEntry(entry, olderRoot); } - /** - * Visits all of the subgroups and subtasks of the newer log's test cases - */ public void visitCaseEntry(CaseEntry entry) { - StringBuffer line = new StringBuffer(indent); - line.append("%%% "); - line.append(entry.getName()); - line.append(", class="); - line.append(entry.getClassName()); - line.append(':'); - os.println(line); - diffText = null; - visitContainer(entry); - if (diffText != null) { - Iterator it = diffText.iterator(); - while (it.hasNext()) os.println((String) it.next()); + LogEntryContainer prevOlderParent = olderParent; + if (olderParent != null) { + olderParent = (LogEntryContainer) olderParent.findMember(entry.getName(), CaseEntry.class); } - diffText = null; - os.println(); + visitCaseEntry(entry, (CaseEntry) olderParent); + olderParent = prevOlderParent; } - /** - * Visits all of the subgroups and subtasks of the newer log's test cases - */ public void visitGroupEntry(GroupEntry entry) { - List oldDiffText = diffText; - diffText = null; - visitContainer(entry); - if (diffText != null) { - StringBuffer line = new StringBuffer(indent); - line.append("+ "); - line.append(entry.getName()); - line.append(':'); - diffText.add(0, line.toString()); - if (oldDiffText != null) diffText.addAll(0, oldDiffText); - } else { - diffText = oldDiffText; + LogEntryContainer prevOlderParent = olderParent; + if (olderParent != null) { + olderParent = (LogEntryContainer) olderParent.findMember(entry.getName(), GroupEntry.class); } + visitGroupEntry(entry, (GroupEntry) olderParent); + olderParent = prevOlderParent; } - - /** - * Prints the average amount of time spent by a task. - */ - public void visitTaskEntry(TaskEntry task) { - int diff = Integer.MAX_VALUE; - TaskEntry olderTask = null; + + public void visitTaskEntry(TaskEntry entry) { + TaskEntry olderEntry = null; if (olderParent != null) { - olderTask = (TaskEntry) olderParent.findMember(task.getName(), TaskEntry.class); - if (olderTask != null && task.getTotalRuns() != 0 && olderTask.getTotalRuns() != 0) { - diff = task.getAverageMillis() - olderTask.getAverageMillis(); - // ignore negligible changes - if (ignoreNegligible && Math.abs(diff) <= threshold) return; - } - } - // print task description - if (diffText == null) diffText = new LinkedList(); // using a list for speedy prepending - StringBuffer line = new StringBuffer(indent); - line.append("- "); - line.append(task.getName()); - line.append(": "); - diffText.add(line.toString()); - - // print new entry performance - printTaskEntry(" newer: ", task); - - // print older entry performance - if (olderTask == null) return; - printTaskEntry(" older: ", olderTask); - - // print difference - if (diff == Integer.MAX_VALUE) return; - line = new StringBuffer(indent); - line.append(" diff : "); - if (Math.abs(diff) > threshold) { - if (diff > 0) line.append("SLOWER"); - else line.append("FASTER"); - line.append(" by "); - line.append(Integer.toString(Math.abs(diff))); - line.append(" ms avg."); - } else { - line.append("NEGLIGIBLE"); + olderEntry = (TaskEntry) olderParent.findMember(entry.getName(), TaskEntry.class); } - diffText.add(line.toString()); + if (ignoreNegligible && isNegligible(entry, olderEntry)) return; + visitTaskEntry(entry, olderEntry); } - protected void printTaskEntry(String prefix, TaskEntry task) { - StringBuffer line = new StringBuffer(indent); - line.append(prefix); - if (task.getTotalRuns() != 0) { - int averageTime = task.getAverageMillis(); - line.append(Integer.toString(averageTime)); - line.append(" ms"); - if (task.getTotalRuns() > 1) { - line.append(" avg. over "); - line.append(Integer.toString(task.getTotalRuns())); - line.append(" runs"); - } - } else { - line.append("skipped!"); - } - diffText.add(line.toString()); + protected boolean isNegligible(TaskEntry newerEntry, TaskEntry olderEntry) { + if (newerEntry.getTotalRuns() == 0 || olderEntry.getTotalRuns() == 0) return false; + int olderMean = olderEntry.getAverageMillis(); + if (olderMean == 0) return true; + int diff = Math.abs(newerEntry.getAverageMillis() - olderMean); + return diff * 100 / olderMean < threshold; } } diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintRawMain.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintRawMain.java deleted file mode 100644 index e44e648f7..000000000 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintRawMain.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.eclipse.team.tests.ccvs.ui.logformatter; - -/* - * (c) Copyright IBM Corp. 2000, 2002. - * All Rights Reserved. - */ - -import java.io.File; -import java.io.PrintStream; - -public class PrintRawMain { - public static void main(String[] args) { - if (args.length != 1) { - System.err.println("Usage: java PrintRawMain <log>"); - return; - } - File file = new File(args[0]); - try { - // read the log - RootEntry root = LogEntry.readLog(file); - - // print header - PrintStream ps = System.out; - ps.println("=== RAW TEST LOG SUMMARY ==="); - ps.println("File: " + file); - ps.println(" Generated: " + root.getTimestamp()); - ps.println(" SDK Build: " + root.getSDKBuildId()); - ps.println(); - - // print the log summary - root.accept(new PrintSummaryVisitor(ps)); - } catch (Exception e) { - System.err.println("An error occurred while parsing: " + file); - e.printStackTrace(); - return; - } - } -} diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintSummaryMain.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintSummaryMain.java new file mode 100644 index 000000000..91e1acfa3 --- /dev/null +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintSummaryMain.java @@ -0,0 +1,116 @@ +package org.eclipse.team.tests.ccvs.ui.logformatter; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; + +import org.xml.sax.SAXException; + +public class PrintSummaryMain { + public static void main(String[] args) { + Parser parser = new Parser(); + if (! parser.parse(args)) { + System.err.println("Usage: <log file> [-out <file>] [-csv] [-raw]"); + System.err.println(" -out <file> : specify the output file, default is console"); + System.err.println(" -csv : produce comma separated values data"); + System.err.println(" -raw : do not merge results from successive iterations"); + return; + } + try { + PrintStream ps = System.out; + try { + if (parser.outputFile != null) ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(parser.outputFile))); + printLog(ps, parser.logFile, parser.csv, parser.raw); + } finally { + if (ps != System.out) ps.close(); + } + } catch (Exception e) { + System.err.println("An error occurred:"); + e.printStackTrace(); + return; + } + } + + private static void printLog(PrintStream ps, File logFile, boolean csv, boolean raw) + throws IOException, SAXException { + // read and merge the log + RootEntry root = LogEntry.readLog(logFile); + if (! raw) { + MergeRunsVisitor mergeVisitor = new MergeRunsVisitor(null); + root.accept(mergeVisitor); + root = mergeVisitor.getMergedRoot(); + } + + // format options + StringBuffer options = new StringBuffer(); + if (raw) options.append("-raw "); + + // format log file + if (csv) { + DelimitedValuesWriter writer = new DelimitedValuesWriter(ps, ",", true /*quoted*/); + // print header + writer.printRecord(new String[] { "Log File", logFile.toString() }); + writer.printRecord(new String[] { "Generated", root.getTimestamp() }); + writer.printRecord(new String[] { "SDK Build", root.getSDKBuildId() }); + writer.endRecord(); + writer.printRecord(new String[] { "Options", "'" + options.toString() }); + writer.endRecord(); + writer.printRecord(new String[] { "Case", "Group", "Task", + "Runs", "Avg. (ms)", "95% C.I. (ms)", "95% C.I. (%)", "Results (ms)" }); + // print quoted CSV data + PrintCSVSummaryVisitor visitor = new PrintCSVSummaryVisitor(writer); + root.accept(visitor); + } else { + // print header + ps.println("=== LOG SUMMARY ==="); + ps.println("File: " + logFile); + ps.println(" Generated: " + root.getTimestamp()); + ps.println(" SDK Build: " + root.getSDKBuildId()); + ps.println("Options: " + options.toString()); + ps.println(); + // print the log summary + root.accept(new PrintTextSummaryVisitor(ps)); + } + } + + private static class Parser extends ArgumentParser { + public File logFile = null; + public File outputFile = null; + public boolean csv = false; + public boolean raw = false; + + protected boolean handleFinished() { + return logFile != null; + } + protected boolean handleArgument(int index, String arg) { + if (index == 0) { + logFile = new File(arg); + } else { + return false; + } + return true; + } + protected boolean handleOption(String option, String arg) { + if ("-out".equals(option)) { + if (arg == null) return false; + outputFile = new File(arg); + } else if ("-csv".equals(option)) { + if (arg != null) return false; + csv = true; + } else if ("-raw".equals(option)) { + if (arg != null) return false; + raw = true; + } else { + return false; + } + return true; + } + } +} diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintTextDiffVisitor.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintTextDiffVisitor.java new file mode 100644 index 000000000..dd56edeed --- /dev/null +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintTextDiffVisitor.java @@ -0,0 +1,139 @@ +package org.eclipse.team.tests.ccvs.ui.logformatter; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import java.io.PrintStream; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class PrintTextDiffVisitor extends PrintDiffVisitor { + private PrintStream os; + private List diffText; // list of things to print + private String indent; + + /** + * Creates a diff visitor that generates text output. + * + * @param os the output stream + * @see PrintDiffVisitor + */ + public PrintTextDiffVisitor(PrintStream os, RootEntry olderRoot, int threshold, boolean ignoreNegligible) { + super(olderRoot, threshold, ignoreNegligible); + this.os = os; + this.diffText = null; + this.indent = ""; + } + + protected void visitRootEntry(RootEntry entry, RootEntry olderEntry) { + entry.acceptChildren(this); + } + + protected void visitCaseEntry(CaseEntry entry, CaseEntry olderEntry) { + String oldIndent = indent; + indent += " "; + StringBuffer line = new StringBuffer(indent); + line.append("%%% "); + line.append(entry.getName()); + line.append(", class="); + line.append(entry.getClassName()); + line.append(':'); + os.println(line); + diffText = null; + entry.acceptChildren(this); + if (diffText != null) { + Iterator it = diffText.iterator(); + while (it.hasNext()) os.println((String) it.next()); + } + diffText = null; + os.println(); + indent = oldIndent; + } + + protected void visitGroupEntry(GroupEntry entry, GroupEntry olderEntry) { + String oldIndent = indent; + List oldDiffText = diffText; + indent += " "; + diffText = null; + entry.acceptChildren(this); + indent = oldIndent; + if (diffText != null) { + StringBuffer line = new StringBuffer(indent); + line.append("+ "); + line.append(entry.getName()); + line.append(':'); + diffText.add(0, line.toString()); + if (oldDiffText != null) diffText.addAll(0, oldDiffText); + } else { + diffText = oldDiffText; + } + } + + protected void visitTaskEntry(TaskEntry entry, TaskEntry olderEntry) { + // print task description + if (diffText == null) diffText = new LinkedList(); // using a list for speedy prepending + StringBuffer line = new StringBuffer(indent); + line.append("- "); + line.append(entry.getName()); + line.append(": "); + diffText.add(line.toString()); + + // print new entry performance + printTaskEntry(" newer: ", entry); + + // print older entry performance + if (olderEntry == null) return; + printTaskEntry(" older: ", olderEntry); + + // print difference + if (entry.getTotalRuns() == 0 || olderEntry.getTotalRuns() == 0) return; + int olderMean = olderEntry.getAverageMillis(); + int diff = entry.getAverageMillis() - olderMean; + line = new StringBuffer(indent); + line.append(" diff : "); + + if (isNegligible(entry, olderEntry)) { + line.append("NEGLIGIBLE"); + } else { + line.append(diff > 0 ? "SLOWER" : "FASTER"); + line.append(" by "); + line.append(Integer.toString(Math.abs(diff))); + line.append(" ms"); + if (olderEntry.getAverageMillis() != 0) { + line.append(" = "); + line.append(Util.formatPercentageRatio(Math.abs(diff), olderMean)); + } + line.append(" avg."); + } + diffText.add(line.toString()); + } + + protected void printTaskEntry(String prefix, TaskEntry task) { + StringBuffer line = new StringBuffer(indent); + line.append(prefix); + if (task.getTotalRuns() != 0) { + int averageTime = task.getAverageMillis(); + line.append(Integer.toString(averageTime)); + line.append(" ms"); + if (task.getTotalRuns() > 1) { + line.append(" avg. over "); + line.append(Integer.toString(task.getTotalRuns())); + line.append(" runs"); + if (averageTime != 0) { + int confidence = task.getConfidenceInterval(); + line.append(" (95% C.I. +/- "); + line.append(Integer.toString(confidence)); + line.append(" ms = "); + line.append(Util.formatPercentageRatio(confidence, averageTime)); + line.append(")"); + } + } + } else { + line.append("skipped!"); + } + diffText.add(line.toString()); + } +} diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintSummaryVisitor.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintTextSummaryVisitor.java index 274c8d2ca..140366165 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintSummaryVisitor.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/PrintTextSummaryVisitor.java @@ -7,7 +7,7 @@ package org.eclipse.team.tests.ccvs.ui.logformatter; import java.io.PrintStream; -public class PrintSummaryVisitor implements ILogEntryVisitor { +public class PrintTextSummaryVisitor implements ILogEntryVisitor { private PrintStream os; private String indent; private int totalAverageTime; @@ -16,7 +16,7 @@ public class PrintSummaryVisitor implements ILogEntryVisitor { * Creates a visitor to print a summary of all entries contained in a log. * @param os the output stream */ - public PrintSummaryVisitor(PrintStream os) { + public PrintTextSummaryVisitor(PrintStream os) { this.os = os; this.indent = ""; this.totalAverageTime = 0; @@ -86,6 +86,14 @@ public class PrintSummaryVisitor implements ILogEntryVisitor { line.append(" avg. over "); line.append(Integer.toString(task.getTotalRuns())); line.append(" runs"); + if (averageTime != 0) { + int confidence = task.getConfidenceInterval(); + line.append(" (95% C.I. +/- "); + line.append(Integer.toString(confidence)); + line.append(" ms = "); + line.append(Util.formatPercentageRatio(confidence, averageTime)); + line.append(")"); + } } } else { line.append("skipped!"); diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/Result.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/Result.java new file mode 100644 index 000000000..af36f54e2 --- /dev/null +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/Result.java @@ -0,0 +1,33 @@ +package org.eclipse.team.tests.ccvs.ui.logformatter; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import org.xml.sax.Attributes; + +/** + * Holds the result of one iteration of tests. + * Note that a test might be run multiple times per iteration, particularly if it + * is of very short duration to reduce sampling error. This behaviour is not supported + * at this time, but will likely be of value in the future. + */ +public class Result { + private int runs; + private int millis; + + public Result(Attributes attributes) { + this(1, Integer.parseInt(attributes.getValue("elapsed"))); + } + public Result(int runs, int millis) { + this.runs = runs; + this.millis = millis; + } + public int getRuns() { + return runs; + } + public int getMillis() { + return millis; + } +} diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/TaskEntry.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/TaskEntry.java index ee6a6ce38..db6f50ee3 100644 --- a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/TaskEntry.java +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/TaskEntry.java @@ -5,11 +5,14 @@ package org.eclipse.team.tests.ccvs.ui.logformatter; * All Rights Reserved. */ +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + import org.xml.sax.Attributes; public class TaskEntry extends LogEntry { - private int totalMillis = 0; - private int totalRuns = 0; + private List /* of Result */ results = new ArrayList(); public TaskEntry(LogEntryContainer parent, Attributes attributes) { this(parent, attributes.getValue("name")); @@ -27,46 +30,71 @@ public class TaskEntry extends LogEntry { * Returns the average number of milliseconds elapsed, or -1 if unknown. */ public int getAverageMillis() { + int totalMillis = 0; + int totalRuns = 0; + for (Iterator it = results.iterator(); it.hasNext();) { + Result result = (Result) it.next(); + totalMillis += result.getMillis(); + totalRuns += result.getRuns(); + } if (totalRuns == 0) return -1; return totalMillis / totalRuns; } /** - * Returns the total number over all runs, or 0 if no runs. + * Returns the standard deviation of the sample. + * sqrt((n * sum(X^2) - sum(X)^2) / (n * (n-1))) + */ + public double getStandardDeviation() { + double sumOfSquares = 0.0, sum = 0.0; + int totalRuns = 0; + for (Iterator it = results.iterator(); it.hasNext();) { + Result result = (Result) it.next(); + if (result.getRuns() == 0) continue; + totalRuns += result.getRuns(); + sum += result.getMillis(); + double average = (double)result.getMillis() / result.getRuns(); + sumOfSquares += average * average * result.getRuns(); + } + if (totalRuns == 0) return 0; + return Math.sqrt((sumOfSquares * totalRuns - sum * sum) / (totalRuns * (totalRuns - 1))); + } + + /** + * Returns a 95% confidence interval from the mean represented by getAverageMillis() + * Uses the formula: + * 1.960 * / sqrt(n) */ - public int getTotalMillis() { - return totalMillis; + public int getConfidenceInterval() { + return (int) (1.960 * getStandardDeviation() / Math.sqrt(getTotalRuns())); } /** * Returns the number of times this task was run. */ public int getTotalRuns() { + int totalRuns = 0; + for (Iterator it = results.iterator(); it.hasNext();) { + Result result = (Result) it.next(); + totalRuns += result.getRuns(); + } return totalRuns; } /** - * Adds a set of runs. - * @param millisElapsed the number of milliseconds elapsed over all runs - * @param runs the number of runs to add + * Returns an array of all Results for this task. */ - public void addRuns(int millisElapsed, int runs) { - totalMillis += millisElapsed; - totalRuns += runs; + public Result[] getResults() { + return (Result[]) results.toArray(new Result[results.size()]); } - /* - * Adds some results corresponding to this task. + /** + * Adds a result. + * @param result the result */ - void addResult(Attributes attributes) { - int elapsed = 0; - int runs = 0; - boolean aborted = false; - String value = attributes.getValue("elapsed"); - if (value != null) { - elapsed = Integer.parseInt(value, 10); - runs = 1; - } - addRuns(elapsed, runs); + public void addResult(Result result) { + results.add(result); } + + } diff --git a/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/Util.java b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/Util.java new file mode 100644 index 000000000..10d38f8ba --- /dev/null +++ b/tests/org.eclipse.team.tests.cvs.core/src/org/eclipse/team/tests/ccvs/ui/logformatter/Util.java @@ -0,0 +1,17 @@ +package org.eclipse.team.tests.ccvs.ui.logformatter; + +/* + * (c) Copyright IBM Corp. 2000, 2002. + * All Rights Reserved. + */ + +import java.text.DecimalFormat; +import java.text.NumberFormat; + +public class Util { + private static final NumberFormat percentageFormat = new DecimalFormat("####0.00%"); + + public static String formatPercentageRatio(int numerator, int denominator) { + return percentageFormat.format((double)numerator / denominator); + } +} |