Merge "Limit the number of commits in LogCommand output"
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
index 8c53dbe..0729ecb 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
@@ -44,19 +44,28 @@
 
 import static org.junit.Assert.assertEquals;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
 import java.util.List;
 
 import org.eclipse.jgit.diff.DiffEntry;
 import org.eclipse.jgit.diff.DiffEntry.ChangeType;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.AbstractTreeIterator;
+import org.eclipse.jgit.treewalk.CanonicalTreeParser;
+import org.eclipse.jgit.treewalk.filter.PathFilter;
 import org.junit.Test;
 
 public class DiffCommandTest extends RepositoryTestCase {
 	@Test
 	public void testDiffModified() throws Exception {
-		write(new File(db.getDirectory().getParent(), "test.txt"), "test");
-		File folder = new File(db.getDirectory().getParent(), "folder");
+		write(new File(db.getWorkTree(), "test.txt"), "test");
+		File folder = new File(db.getWorkTree(), "folder");
 		folder.mkdir();
 		write(new File(folder, "folder.txt"), "folder");
 		Git git = new Git(db);
@@ -64,7 +73,8 @@ public void testDiffModified() throws Exception {
 		git.commit().setMessage("Initial commit").call();
 		write(new File(folder, "folder.txt"), "folder change");
 
-		List<DiffEntry> entries = git.diff().call();
+		OutputStream out = new ByteArrayOutputStream();
+		List<DiffEntry> entries = git.diff().setOutputStream(out).call();
 		assertEquals(1, entries.size());
 		assertEquals(ChangeType.MODIFY, entries.get(0)
 				.getChangeType());
@@ -72,12 +82,24 @@ public void testDiffModified() throws Exception {
 				.getOldPath());
 		assertEquals("folder/folder.txt", entries.get(0)
 				.getNewPath());
+
+		String actual = out.toString();
+		String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
+				+ "index 0119635..95c4c65 100644\n"
+				+ "--- a/folder/folder.txt\n"
+				+ "+++ b/folder/folder.txt\n"
+				+ "@@ -1 +1 @@\n"
+				+ "-folder\n"
+				+ "\\ No newline at end of file\n"
+				+ "+folder change\n"
+				+ "\\ No newline at end of file\n";
+		assertEquals(expected.toString(), actual);
 	}
 
 	@Test
 	public void testDiffCached() throws Exception {
-		write(new File(db.getDirectory().getParent(), "test.txt"), "test");
-		File folder = new File(db.getDirectory().getParent(), "folder");
+		write(new File(db.getWorkTree(), "test.txt"), "test");
+		File folder = new File(db.getWorkTree(), "folder");
 		folder.mkdir();
 		Git git = new Git(db);
 		git.add().addFilepattern(".").call();
@@ -85,7 +107,9 @@ public void testDiffCached() throws Exception {
 		write(new File(folder, "folder.txt"), "folder");
 		git.add().addFilepattern(".").call();
 
-		List<DiffEntry> entries = git.diff().setCached(true).call();
+		OutputStream out = new ByteArrayOutputStream();
+		List<DiffEntry> entries = git.diff().setOutputStream(out)
+				.setCached(true).call();
 		assertEquals(1, entries.size());
 		assertEquals(ChangeType.ADD, entries.get(0)
 				.getChangeType());
@@ -93,5 +117,79 @@ public void testDiffCached() throws Exception {
 				.getOldPath());
 		assertEquals("folder/folder.txt", entries.get(0)
 				.getNewPath());
+
+		String actual = out.toString();
+		String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
+				+ "new file mode 100644\n"
+				+ "index 0000000..0119635\n"
+				+ "--- /dev/null\n"
+				+ "+++ b/folder/folder.txt\n"
+				+ "@@ -0,0 +1 @@\n"
+				+ "+folder\n"
+				+ "\\ No newline at end of file\n";
+		assertEquals(expected.toString(), actual);
+	}
+
+	@Test
+	public void testDiffTwoCommits() throws Exception {
+		write(new File(db.getWorkTree(), "test.txt"), "test");
+		File folder = new File(db.getWorkTree(), "folder");
+		folder.mkdir();
+		write(new File(folder, "folder.txt"), "folder");
+		Git git = new Git(db);
+		git.add().addFilepattern(".").call();
+		git.commit().setMessage("Initial commit").call();
+		write(new File(folder, "folder.txt"), "folder change");
+		git.add().addFilepattern(".").call();
+		git.commit().setMessage("second commit").call();
+		write(new File(folder, "folder.txt"), "second folder change");
+		git.add().addFilepattern(".").call();
+		git.commit().setMessage("third commit").call();
+
+		// bad filter
+		DiffCommand diff = git.diff().setShowNameAndStatusOnly(true)
+				.setPathFilter(PathFilter.create("test.txt"))
+				.setOldTree(getTreeIterator("HEAD^^"))
+				.setNewTree(getTreeIterator("HEAD^"));
+		List<DiffEntry> entries = diff.call();
+		assertEquals(0, entries.size());
+
+		// no filter, two commits
+		OutputStream out = new ByteArrayOutputStream();
+		diff = git.diff().setOutputStream(out)
+				.setOldTree(getTreeIterator("HEAD^^"))
+				.setNewTree(getTreeIterator("HEAD^"));
+		entries = diff.call();
+		assertEquals(1, entries.size());
+		assertEquals(ChangeType.MODIFY, entries.get(0).getChangeType());
+		assertEquals("folder/folder.txt", entries.get(0).getOldPath());
+		assertEquals("folder/folder.txt", entries.get(0).getNewPath());
+
+		String actual = out.toString();
+		String expected = "diff --git a/folder/folder.txt b/folder/folder.txt\n"
+				+ "index 0119635..95c4c65 100644\n"
+				+ "--- a/folder/folder.txt\n"
+				+ "+++ b/folder/folder.txt\n"
+				+ "@@ -1 +1 @@\n"
+				+ "-folder\n"
+				+ "\\ No newline at end of file\n"
+				+ "+folder change\n"
+				+ "\\ No newline at end of file\n";
+		assertEquals(expected.toString(), actual);
+	}
+
+	private AbstractTreeIterator getTreeIterator(String name)
+			throws IOException {
+		final ObjectId id = db.resolve(name);
+		if (id == null)
+			throw new IllegalArgumentException(name);
+		final CanonicalTreeParser p = new CanonicalTreeParser();
+		final ObjectReader or = db.newObjectReader();
+		try {
+			p.reset(or, new RevWalk(db).parseTree(id));
+			return p;
+		} finally {
+			or.release();
+		}
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java
index cf80316..5fff5b5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DiffCommand.java
@@ -44,7 +44,9 @@
 
 import static org.eclipse.jgit.lib.Constants.HEAD;
 
+import java.io.BufferedOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.util.List;
 
 import org.eclipse.jgit.JGitText;
@@ -76,8 +78,9 @@ public class DiffCommand extends GitCommand<List<DiffEntry>> {
 
 	private TreeFilter pathFilter = TreeFilter.ALL;
 
-	// TODO: fixed to true for now
-	private boolean showNameAndStatusOnly = true;
+	private boolean showNameAndStatusOnly;
+
+	private OutputStream out;
 
 	/**
 	 * @param repo
@@ -95,7 +98,8 @@ protected DiffCommand(Repository repo) {
 	 * @return a DiffEntry for each path which is different
 	 */
 	public List<DiffEntry> call() throws GitAPIException, IOException {
-		final DiffFormatter diffFmt = new DiffFormatter(null);
+		final DiffFormatter diffFmt = new DiffFormatter(
+				new BufferedOutputStream(out));
 		diffFmt.setRepository(repo);
 		try {
 			if (cached) {
@@ -122,11 +126,13 @@ public List<DiffEntry> call() throws GitAPIException, IOException {
 
 			diffFmt.setPathFilter(pathFilter);
 
+			List<DiffEntry> result = diffFmt.scan(oldTree, newTree);
 			if (showNameAndStatusOnly) {
-				return diffFmt.scan(oldTree, newTree);
+				return result;
 			} else {
-				// TODO: not implemented yet
-				throw new UnsupportedOperationException();
+				diffFmt.format(result);
+				diffFmt.flush();
+				return result;
 			}
 		} finally {
 			diffFmt.release();
@@ -180,10 +186,17 @@ public DiffCommand setNewTree(AbstractTreeIterator newTree) {
 	 * @return this instance
 	 */
 	public DiffCommand setShowNameAndStatusOnly(boolean showNameAndStatusOnly) {
-		// TODO: not implemented yet
-		if (!showNameAndStatusOnly)
-			throw new UnsupportedOperationException();
 		this.showNameAndStatusOnly = showNameAndStatusOnly;
 		return this;
 	}
+
+	/**
+	 * @param out
+	 *            the stream to write line data
+	 * @return this instance
+	 */
+	public DiffCommand setOutputStream(OutputStream out) {
+		this.out = out;
+		return this;
+	}
 }
\ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
index e2757e6..33755dd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
@@ -581,7 +581,9 @@ public void format(AbstractTreeIterator a, AbstractTreeIterator b)
 	}
 
 	/**
-	 * Format a patch script from a list of difference entries.
+	 * Format a patch script from a list of difference entries. Requires
+	 * {@link #scan(AbstractTreeIterator, AbstractTreeIterator)} to have been
+	 * called first.
 	 *
 	 * @param entries
 	 *            entries describing the affected files.