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());
     }
 
 }