diff --git a/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/FileList.java b/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/FileList.java index 312c9e3c832abd8d1a0d0e1c324928bd87107133..ff447472b5e792b8294432c4afaefe9613bd0ca8 100644 --- a/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/FileList.java +++ b/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/FileList.java @@ -51,6 +51,12 @@ import de.fu_berlin.inf.dpp.util.xstream.IPathConverter; * A FileList is a list of resources - files and folders - which can be compared * to other file lists. Folders are denoted by a trailing separator. * + * NOTE: As computation of a FileList involves a complete rescan of the project, + * creating new instances should be avoided. TODO: This class should be split up + * to clearly separate between file lists and differences between file lists. + * Fields like removed, added, etc. do not make sense for plain lists and just + * add confusion. + * * @author rdjemili */ @XStreamAlias("fileList") @@ -138,16 +144,29 @@ public class FileList { this.unaltered.putAll(this.all); } - // TODO invert diff direction /** - * Returns a new FileList which contains the diff from the two FileLists. + * Returns a new FileList which contains the difference of two FileLists, + * consisting of files missing in <code>other</code> but present in + * <code>this</code> and files in <code>other</code> which are not present + * in <code>this</code>. * * @param other - * the other FileList with which this FileList is compared with. + * the <code>FileList</code> to compare to. + * + * @return a new <code>FileList</code> which contains the difference + * information of the two <code>FileList</code>s: + * <code>result.removed</code> contains paths present in + * <code>this.all</code> but not in <code>other.all</code>. + * <code>result.added</code> contains paths present in + * <code>other.all</code> but not in <code>this.all</code>. + * <code>result.unaltered</code>/<code>results.altered</code> + * contain paths where the checksum is equal to/differs between + * <code>this</code> and <code>other</code>. <code>result.all</code> + * contains all paths from <code>other</code>. * - * @return a new FileList which contains the diff information from the two - * FileLists. The diff contains the operations which are needed to - * get from this FileList to the other FileList. + * The diff contains the operations which are needed to - * get from + * <code>this</code> <code>FileList</code> to the <code>other</code> + * <code>FileList</code>. */ public FileList diff(FileList other) { FileList result = new FileList(); @@ -188,21 +207,28 @@ public class FileList { } /** - * @return the amount in percentage by which this file list has the same - * files as the other file list. Returns 100 only if the given - * FileList matches perfectly. + * Calculate an approximation of how equal <code>this</code> + * <code>FileList</code> is to <code>other</code>. NOTE: This is a + * long-running method linear to size of the length of the two file lists. + * + * @param other + * @return Percentage of "sameness" of <code>this</code> and + * <code>other</code> counting the number of identical files + * relative to the size of the larger list. 100 means identical + * <code>FileList</code>s. */ - public int match(FileList other) { - int nPaths = getPaths().size(); + public int computeMatch(FileList other) { + // calculate "sameness" of ratio of longer list + int nPaths = Math.max(getPaths().size(), other.getPaths().size()); if (nPaths == 0 && other.getPaths().isEmpty()) return 100; // both are empty -> perfect match - if (nPaths == 0) { + if (nPaths == 0) { // other is empty return 0; } else { - FileList diff = this.diff(other); - int nUnalteredPaths = diff.getUnalteredPaths().size(); + FileList difference = this.diff(other); + int nUnalteredPaths = difference.getUnalteredPaths().size(); if (nPaths == nUnalteredPaths) { return 100; } else { @@ -211,6 +237,26 @@ public class FileList { } } + /** + * Calculate an approximation of how equal <code>this</code> + * <code>FileList</code> is to <code>project</code>. NOTE: This is a + * long-running method linear to size of the length of the two file lists. + * + * @param project + * @return Percentage of "sameness" of <code>this</code> and + * <code>other</code> counting the number of identical files + * relative to the size of the larger list. 100 means identical + * <code>FileList</code>s. On error, returns 0. + */ + public int computeMatch(IProject project) { + try { + return this.computeMatch(new FileList(project)); + } catch (CoreException e) { + log.error("Failed to generate FileList for match computation", e); + } + return 0; + } + protected static synchronized XStream getXStream() { if (xstream == null) { xstream = new XStream(); @@ -441,5 +487,4 @@ public class FileList { monitor.done(); return result; } - } diff --git a/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/ui/wizards/EnterProjectNamePage.java b/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/ui/wizards/EnterProjectNamePage.java index 2041aa5582166d8931afb07a66158f422ec7b745..ded823aa6c0b952da6473bd2058c39987e5e7f05 100644 --- a/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/ui/wizards/EnterProjectNamePage.java +++ b/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/ui/wizards/EnterProjectNamePage.java @@ -82,10 +82,9 @@ class EnterProjectNamePage extends WizardPage { this.updateProjectStatusResult.setText("Your project " + project.getName() + " matches with " - + JoinSessionWizardUtils - .getMatch(this.joinSessionWizard.process - .getRemoteFileList(), project) + "% accuracy.\n" - + "This fact will used to shorten the process of " + + this.joinSessionWizard.process.getRemoteFileList() + .computeMatch(project) + "% accuracy.\n" + + "This fact will be used to shorten the process of " + "downloading the remote project."); this.updateProjectText.setText(this.similarProject.getName()); diff --git a/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/ui/wizards/JoinSessionWizard.java b/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/ui/wizards/JoinSessionWizard.java index 365c7b4217ff7936280a6ef01596e7905a642e91..1f311a04c805f03bad2347f77ca13fbe9d007dc6 100644 --- a/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/ui/wizards/JoinSessionWizard.java +++ b/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/ui/wizards/JoinSessionWizard.java @@ -183,8 +183,7 @@ public class JoinSessionWizard extends Wizard { * and if there are differences between the remote and local project. */ if (namePage.overwriteProjectResources() - && JoinSessionWizardUtils.getMatch(process.getRemoteFileList(), - source) != 100) { + && process.getRemoteFileList().computeMatch(source) != 100) { if (!confirmOverwritingProjectResources(source.getName())) return false; } diff --git a/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/ui/wizards/JoinSessionWizardUtils.java b/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/ui/wizards/JoinSessionWizardUtils.java index bf86a4a51061cf3b29558107ca14292eadff74c4..8aa5bdda876112096f6ff1f08289df80d10eb9b7 100644 --- a/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/ui/wizards/JoinSessionWizardUtils.java +++ b/de.fu_berlin.inf.dpp/src/de/fu_berlin/inf/dpp/ui/wizards/JoinSessionWizardUtils.java @@ -9,7 +9,6 @@ import org.apache.log4j.Logger; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; @@ -81,16 +80,6 @@ public class JoinSessionWizardUtils { return runner.project; } - public static int getMatch(FileList remoteFileList, IProject project) { - try { - return remoteFileList.match(new FileList(project)); - } catch (CoreException e) { - log.debug("Couldn't calculate match for project " + project, e); - - return -1; - } - } - /** * Return the best match among all project from workspace with the given * remote file list or null if no best match could be found or if the @@ -98,7 +87,7 @@ public class JoinSessionWizardUtils { * * To be considered a match, projects have to match at least 80%. */ - public static IProject getLocalProject(FileList remoteFileList, + public static IProject getLocalProject(FileList hostFileList, IProgressMonitor monitor) throws InterruptedException { IWorkspace workspace = ResourcesPlugin.getWorkspace(); @@ -123,8 +112,7 @@ public class JoinSessionWizardUtils { continue; } - int matchScore = JoinSessionWizardUtils.getMatch(remoteFileList, - projects[i]); + int matchScore = hostFileList.computeMatch(projects[i]); if (matchScore > bestMatchScore) { bestMatchScore = matchScore; diff --git a/de.fu_berlin.inf.dpp/test/src/de/fu_berlin/inf/dpp/net/FileListTest.java b/de.fu_berlin.inf.dpp/test/src/de/fu_berlin/inf/dpp/net/FileListTest.java index 923d69ad21d0a799ed0ede4724fb513c9c80db86..c6ede0976b43e8d60a5468299bbe10f512836321 100644 --- a/de.fu_berlin.inf.dpp/test/src/de/fu_berlin/inf/dpp/net/FileListTest.java +++ b/de.fu_berlin.inf.dpp/test/src/de/fu_berlin/inf/dpp/net/FileListTest.java @@ -34,146 +34,163 @@ import de.fu_berlin.inf.dpp.test.stubs.FileStub; /** * TODO [TEST] Add Testcases for non-existing files + * florianthiel: Does FileList care about existence of files? * * TODO [TEST] Add Testcases for derived files + * florianthiel: What are "derived files" in this context? */ public class FileListTest extends TestCase { - private IFile[] files; - private IFile[] otherFiles; - private FileList fileList; - private FileList otherFileList; - private FileList emptyFileList; + protected IFile fileInRoot1 = new FileStub("root1", "fileInRoot1"); + protected IFile fileInRoot2 = new FileStub("root2", "fileInRoot2"); + protected IFile fileInSubDir1 = new FileStub("subdir/file1", "fileInSubDir1"); + protected IFile fileInSubDir2 = new FileStub("subdir/file2", "fileInSubDir2"); + protected IFile fileInSubDir1changed = new FileStub("subdir/file1", + "changed fileInSubDir1"); + + protected IFile[] threeFileArray = new IFile[] { fileInRoot1, fileInRoot2, + fileInSubDir1 }; + + protected FileList threeEntryList; + protected FileList fourEntryList; // contains one additional entry + // in respect to threeEntryList + protected FileList modifiedFourEntryList; // contains one modified entry in + // respect to fourEntryList + protected FileList emptyFileList; @Override protected void setUp() throws Exception { - files = new IFile[] { new FileStub("root.txt", "this in the root"), - new FileStub("foo/bar/unit.java", "class Test {}"), - new FileStub("foo/bar/test.txt", "") }; - fileList = new FileList(files); - - otherFiles = new IFile[] { - new FileStub("root.txt", "this in the root"), - new FileStub("foo/bar/unit.java", "class Test {void foo(){}}"), - new FileStub("foo/test.txt", "another test content") }; - otherFileList = new FileList(otherFiles); + threeEntryList = new FileList(new IFile[] { fileInRoot1, fileInRoot2, + fileInSubDir1 }); + fourEntryList = new FileList(new IFile[] { fileInRoot1, fileInRoot2, + fileInSubDir1, fileInSubDir2 }); + modifiedFourEntryList = new FileList(new IFile[] { fileInRoot1, + fileInRoot2, fileInSubDir1changed, fileInSubDir2 }); emptyFileList = new FileList(); } public void testGetFilePaths() { - List<IPath> paths = fileList.getPaths(); + List<IPath> paths = threeEntryList.getPaths(); - assertPaths(new String[] { "root.txt", "foo/bar/unit.java", - "foo/bar/test.txt" }, paths); + assertPaths(new String[] { "root1", "root2", "subdir/file1" }, paths); } public void testGetFileUnalteredPaths() { - Collection<IPath> paths = fileList.getUnalteredPaths(); + Collection<IPath> paths = threeEntryList.getUnalteredPaths(); - assertPaths(new String[] { "root.txt", "foo/bar/unit.java", - "foo/bar/test.txt" }, paths); + assertPaths(new String[] { "root1", "root2", "subdir/file1" }, paths); } public void testDiffGetAddedFilePaths() { - Collection<IPath> paths = fileList.diff(otherFileList).getAddedPaths(); + Collection<IPath> paths = threeEntryList.diff(fourEntryList) + .getAddedPaths(); - assertPaths(new String[] { "foo/test.txt" }, paths); + assertPaths(new String[] { "subdir/file2" }, paths); } public void testReversedDiffGetAddedFilePaths() { - Collection<IPath> paths = otherFileList.diff(fileList).getAddedPaths(); + Collection<IPath> paths = fourEntryList.diff(threeEntryList) + .getAddedPaths(); - assertPaths(new String[] { "foo/bar/test.txt" }, paths); + assertPaths(new String[] {}, paths); } public void testDiffGetRemovedFilePaths() { - Collection<IPath> paths = fileList.diff(otherFileList) + Collection<IPath> paths = fourEntryList.diff(threeEntryList) .getRemovedPaths(); - assertPaths(new String[] { "foo/bar/test.txt" }, paths); + assertPaths(new String[] { "subdir/file2" }, paths); } public void testReversedDiffGetRemovedFilePaths() { - Collection<IPath> paths = otherFileList.diff(fileList) + Collection<IPath> paths = threeEntryList.diff(fourEntryList) .getRemovedPaths(); - assertPaths(new String[] { "foo/test.txt" }, paths); + assertPaths(new String[] {}, paths); } public void testDiffGetAlteredFilePaths() { - Collection<IPath> paths = fileList.diff(otherFileList) + Collection<IPath> paths = fourEntryList.diff(modifiedFourEntryList) .getAlteredPaths(); - assertPaths(new String[] { "foo/bar/unit.java" }, paths); + assertPaths(new String[] { "subdir/file1" }, paths); } public void testReversedDiffGetAlteredFilePaths() { - Collection<IPath> paths = otherFileList.diff(fileList) + Collection<IPath> paths = modifiedFourEntryList.diff(fourEntryList) + .getAlteredPaths(); + + assertPaths(new String[] { "subdir/file1" }, paths); + } + + public void testDiffGetAlteredFilesAddedFiles() { + Collection<IPath> paths = threeEntryList.diff(fourEntryList) .getAlteredPaths(); - assertPaths(new String[] { "foo/bar/unit.java" }, paths); + assertPaths(new String[] {}, paths); } public void testDiffGetUnalteredFilePaths() { - Collection<IPath> paths = fileList.diff(otherFileList) + Collection<IPath> paths = fourEntryList.diff(modifiedFourEntryList) .getUnalteredPaths(); - assertPaths(new String[] { "root.txt" }, paths); + assertPaths(new String[] { "root1", "root2", "subdir/file2" }, paths); } public void testReversedDiffGetUnalteredFilePaths() { - Collection<IPath> paths = otherFileList.diff(fileList) + Collection<IPath> paths = modifiedFourEntryList.diff(threeEntryList) .getUnalteredPaths(); - assertPaths(new String[] { "root.txt" }, paths); + assertPaths(new String[] { "root1", "root2" }, paths); } public void testDiffGetFilePaths() { - Collection<IPath> paths = fileList.diff(otherFileList).getPaths(); + Collection<IPath> paths = threeEntryList.diff(modifiedFourEntryList) + .getPaths(); - assertPaths(new String[] { "root.txt", "foo/bar/unit.java", - "foo/test.txt" }, paths); + assertPaths(new String[] { "root1", "root2", "subdir/file2", + "subdir/file1" }, paths); - paths = emptyFileList.diff(fileList).getPaths(); - assertPaths(new String[] { "root.txt", "foo/bar/unit.java", - "foo/bar/test.txt" }, paths); - paths = fileList.diff(emptyFileList).getRemovedPaths(); - assertPaths(new String[] { "root.txt", "foo/bar/unit.java", - "foo/bar/test.txt" }, paths); + paths = emptyFileList.diff(threeEntryList).getPaths(); + assertPaths(new String[] { "root1", "root2", "subdir/file1" }, paths); + paths = threeEntryList.diff(emptyFileList).getRemovedPaths(); + assertPaths(new String[] { "root1", "root2", "subdir/file1" }, paths); } public void testMatch() { - assertEquals(33, fileList.match(otherFileList)); - assertEquals(33, otherFileList.match(fileList)); - assertEquals(100, fileList.match(fileList)); - assertEquals(0, fileList.match(emptyFileList)); - assertEquals(0, emptyFileList.match(fileList)); - assertEquals(100, emptyFileList.match(emptyFileList)); + assertEquals(75, threeEntryList.computeMatch(fourEntryList)); + assertEquals(75, fourEntryList.computeMatch(threeEntryList)); + assertEquals(100, threeEntryList.computeMatch(threeEntryList)); + assertEquals(0, threeEntryList.computeMatch(emptyFileList)); + assertEquals(0, emptyFileList.computeMatch(threeEntryList)); + assertEquals(50, threeEntryList.computeMatch(modifiedFourEntryList)); + assertEquals(50, modifiedFourEntryList.computeMatch(threeEntryList)); } public void testEquals() throws CoreException { - FileList sameFileList = new FileList(files); - assertEquals(fileList, sameFileList); + FileList sameFileList = new FileList(threeFileArray); + assertEquals(threeEntryList, sameFileList); assertEquals(emptyFileList, emptyFileList); - assertFalse(fileList.equals(otherFileList)); - assertFalse(emptyFileList.equals(otherFileList)); + assertFalse(threeEntryList.equals(fourEntryList)); + assertFalse(emptyFileList.equals(threeEntryList)); } public void testRoundtripSerialization() { - - FileList replicated = FileList.fromXML(fileList.toXML()); - assertEquals(fileList, replicated); + FileList replicated = FileList.fromXML(threeEntryList.toXML()); + assertEquals(threeEntryList, replicated); } private void assertPaths(String[] expected, Collection<IPath> actual) { for (int i = 0; i < expected.length; i++) { Path path = new Path(expected[i]); - assertTrue(actual.contains(path)); + assertTrue("Expected " + path + " to appear in: " + actual, actual + .contains(path)); } - assertEquals(expected.length, actual.size()); + assertEquals("Expected: '" + expected.toString() + "' actual: '" + + actual + "'", expected.length, actual.size()); } }