diff options
Diffstat (limited to 'org.eclipse.jgit.test')
9 files changed, 937 insertions, 3 deletions
diff --git a/org.eclipse.jgit.test/.settings/org.eclipse.jdt.ui.prefs b/org.eclipse.jgit.test/.settings/org.eclipse.jdt.ui.prefs index 9adc9b1d31..476f78fa9f 100644 --- a/org.eclipse.jgit.test/.settings/org.eclipse.jdt.ui.prefs +++ b/org.eclipse.jgit.test/.settings/org.eclipse.jdt.ui.prefs @@ -1,8 +1,8 @@ -#Sat Oct 31 14:53:06 PDT 2009 +#Tue Jan 05 11:30:06 PST 2010 eclipse.preferences.version=1 editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true -formatter_profile=_JGit -formatter_settings_version=10 +formatter_profile=_JGit Format +formatter_settings_version=11 internal.default.compliance=default org.eclipse.jdt.ui.ignorelowercasenames=true org.eclipse.jdt.ui.importorder=java;javax;org;com; diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/.gitattributes b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/.gitattributes new file mode 100644 index 0000000000..c5831d9a8b --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/.gitattributes @@ -0,0 +1,3 @@ +*.patch -crlf +*Image -crlf +*.out -crlf diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffTestDataGenerator.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffTestDataGenerator.java new file mode 100644 index 0000000000..c403112149 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffTestDataGenerator.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2009, Christian Halstrick <christian.halstrick@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.diff; + +public class DiffTestDataGenerator { + /** + * Generate sequence of characters in ascending order. The first character + * is a space. All subsequent characters have an ASCII code one greater then + * the ASCII code of the preceding character. On exception: the character + * following which follows '~' is again a ' '. + * + * @param len + * length of the String to be returned + * @return the sequence of characters as String + */ + public static String generateSequence(int len) { + return generateSequence(len, 0, 0); + } + + /** + * Generate sequence of characters similar to the one returned by + * {@link #generateSequence(int)}. But this time in each chunk of + * <skipPeriod> characters the last <skipLength> characters are left out. By + * calling this method twice with two different prime skipPeriod values and + * short skipLength values you create test data which is similar to what + * programmers do to their source code - huge files with only few + * insertions/deletions/changes. + * + * @param len + * length of the String to be returned + * @param skipPeriod + * @param skipLength + * @return the sequence of characters as String + */ + public static String generateSequence(int len, int skipPeriod, + int skipLength) { + StringBuilder text = new StringBuilder(len); + int skipStart = skipPeriod - skipLength; + int skippedChars = 0; + for (int i = 0; i - skippedChars < len; ++i) { + if (skipPeriod == 0 || i % skipPeriod < skipStart) { + text.append((char) (32 + i % 95)); + } else { + skippedChars++; + } + } + return text.toString(); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/MyersDiffPerformanceTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/MyersDiffPerformanceTest.java new file mode 100644 index 0000000000..fe63e3d183 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/MyersDiffPerformanceTest.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2009, Christian Halstrick <christian.halstrick@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.diff; + +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +import junit.framework.TestCase; + +import org.eclipse.jgit.util.CPUTimeStopWatch; + +/** + * Test cases for the performance of the diff implementation. The tests test + * that the performance of the MyersDiff algorithm is really O(N*D). Means the + * time for computing the diff between a and b should depend on the product of + * a.length+b.length and the number of found differences. The tests compute + * diffs between chunks of different length, measure the needed time and check + * that time/(N*D) does not differ more than a certain factor (currently 10) + */ +public class MyersDiffPerformanceTest extends TestCase { + private static final long longTaskBoundary = 5000000000L; + + private static final int minCPUTimerTicks = 10; + + private static final int maxFactor = 15; + + private CPUTimeStopWatch stopwatch=CPUTimeStopWatch.createInstance(); + + public class PerfData { + private NumberFormat fmt = new DecimalFormat("#.##E0"); + + public long runningTime; + + public long D; + + public long N; + + private double p1 = -1; + + private double p2 = -1; + + public double perf1() { + if (p1 < 0) + p1 = runningTime / ((double) N * D); + return p1; + } + + public double perf2() { + if (p2 < 0) + p2 = runningTime / ((double) N * D * D); + return p2; + } + + public String toString() { + return ("diffing " + N / 2 + " bytes took " + runningTime + + " ns. N=" + N + ", D=" + D + ", time/(N*D):" + + fmt.format(perf1()) + ", time/(N*D^2):" + fmt + .format(perf2())); + } + } + + public static Comparator<PerfData> getComparator(final int whichPerf) { + return new Comparator<PerfData>() { + public int compare(PerfData o1, PerfData o2) { + double p1 = (whichPerf == 1) ? o1.perf1() : o1.perf2(); + double p2 = (whichPerf == 1) ? o2.perf1() : o2.perf2(); + return (p1 < p2) ? -1 : (p1 > p2) ? 1 : 0; + } + }; + } + + public void test() { + if (stopwatch!=null) { + List<PerfData> perfData = new LinkedList<PerfData>(); + perfData.add(test(10000)); + perfData.add(test(20000)); + perfData.add(test(50000)); + perfData.add(test(80000)); + perfData.add(test(99999)); + perfData.add(test(999999)); + + Comparator<PerfData> c = getComparator(1); + double factor = Collections.max(perfData, c).perf1() + / Collections.min(perfData, c).perf1(); + assertTrue( + "minimun and maximum of performance-index t/(N*D) differed too much. Measured factor of " + + factor + + " (maxFactor=" + + maxFactor + + "). Perfdata=<" + perfData.toString() + ">", + factor < maxFactor); + } + } + + /** + * Tests the performance of MyersDiff for texts which are similar (not + * random data). The CPU time is measured and returned. Because of bad + * accuracy of CPU time information the diffs are repeated. During each + * repetition the interim CPU time is checked. The diff operation is + * repeated until we have seen the CPU time clock changed its value at least + * {@link #minCPUTimerTicks} times. + * + * @param characters + * the size of the diffed character sequences. + * @return performance data + */ + private PerfData test(int characters) { + PerfData ret = new PerfData(); + String a = DiffTestDataGenerator.generateSequence(characters, 971, 3); + String b = DiffTestDataGenerator.generateSequence(characters, 1621, 5); + CharArray ac = new CharArray(a); + CharArray bc = new CharArray(b); + MyersDiff myersDiff = null; + int cpuTimeChanges = 0; + long lastReadout = 0; + long interimTime = 0; + int repetitions = 0; + stopwatch.start(); + while (cpuTimeChanges < minCPUTimerTicks && interimTime < longTaskBoundary) { + myersDiff = new MyersDiff(ac, bc); + repetitions++; + interimTime = stopwatch.readout(); + if (interimTime != lastReadout) { + cpuTimeChanges++; + lastReadout = interimTime; + } + } + ret.runningTime = stopwatch.stop() / repetitions; + ret.N = (ac.size() + bc.size()); + ret.D = myersDiff.getEdits().size(); + + return ret; + } + + private static class CharArray implements Sequence { + private final char[] array; + + public CharArray(String s) { + array = s.toCharArray(); + } + + public int size() { + return array.length; + } + + public boolean equals(int i, Sequence other, int j) { + CharArray o = (CharArray) other; + return array[i] == o.array[j]; + } + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/MyersDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/MyersDiffTest.java new file mode 100644 index 0000000000..c91348ffe6 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/MyersDiffTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2009, Johannes E. Schindelin + * Copyright (C) 2009, Johannes Schindelin <johannes.schindelin@gmx.de> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.diff; + +import junit.framework.TestCase; + +public class MyersDiffTest extends TestCase { + public void testAtEnd() { + assertDiff("HELLO", "HELL", " -4,1 +4,0"); + } + + public void testAtStart() { + assertDiff("Git", "JGit", " -0,0 +0,1"); + } + + public void testSimple() { + assertDiff("HELLO WORLD", "LOW", + " -0,3 +0,0 -5,1 +2,0 -7,4 +3,0"); + // is ambiguous, could be this, too: + // " -0,2 +0,0 -3,1 +1,0 -5,1 +2,0 -7,4 +3,0" + } + + public void assertDiff(String a, String b, String edits) { + MyersDiff diff = new MyersDiff(toCharArray(a), toCharArray(b)); + assertEquals(edits, toString(diff.getEdits())); + } + + private static String toString(EditList list) { + StringBuilder builder = new StringBuilder(); + for (Edit e : list) + builder.append(" -" + e.beginA + + "," + (e.endA - e.beginA) + + " +" + e.beginB + "," + (e.endB - e.beginB)); + return builder.toString(); + } + + private static CharArray toCharArray(String s) { + return new CharArray(s); + } + + protected static String toString(Sequence seq, int begin, int end) { + CharArray a = (CharArray)seq; + return new String(a.array, begin, end - begin); + } + + protected static String toString(CharArray a, CharArray b, + int x, int k) { + return "(" + x + "," + (k + x) + + (x < 0 ? '<' : + (x >= a.array.length ? + '>' : a.array[x])) + + (k + x < 0 ? '<' : + (k + x >= b.array.length ? + '>' : b.array[k + x])) + + ")"; + } + + private static class CharArray implements Sequence { + char[] array; + public CharArray(String s) { array = s.toCharArray(); } + public int size() { return array.length; } + public boolean equals(int i, Sequence other, int j) { + CharArray o = (CharArray)other; + return array[i] == o.array[j]; + } + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java new file mode 100644 index 0000000000..d12fae7c19 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/MergeAlgorithmTest.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2009, Christian Halstrick <christian.halstrick@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.merge; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import junit.framework.TestCase; + +import org.eclipse.jgit.diff.RawText; +import org.eclipse.jgit.lib.Constants; + +public class MergeAlgorithmTest extends TestCase { + MergeFormatter fmt=new MergeFormatter(); + + // the texts which are used in this merge-tests are constructed by + // concatenating fixed chunks of text defined by the String constants + // A..Y. The common base text is always the text A+B+C+D+E+F+G+H+I+J. + // The two texts being merged are constructed by deleting some chunks + // or inserting new chunks. Some of the chunks are one-liners, others + // contain more than one line. + private static final String A = "aaa\n"; + private static final String B = "bbbbb\nbb\nbbb\n"; + private static final String C = "c\n"; + private static final String D = "dd\n"; + private static final String E = "ee\n"; + private static final String F = "fff\nff\n"; + private static final String G = "gg\n"; + private static final String H = "h\nhhh\nhh\n"; + private static final String I = "iiii\n"; + private static final String J = "jj\n"; + private static final String Z = "zzz\n"; + private static final String Y = "y\n"; + + // constants which define how conflict-regions are expected to be reported. + private static final String XXX_0 = "<<<<<<< O\n"; + private static final String XXX_1 = "=======\n"; + private static final String XXX_2 = ">>>>>>> T\n"; + + // the common base from which all merges texts derive from + String base=A+B+C+D+E+F+G+H+I+J; + + // the following constants define the merged texts. The name of the + // constants describe how they are created out of the common base. E.g. + // the constant named replace_XYZ_by_MNO stands for the text which is + // created from common base by replacing first chunk X by chunk M, then + // Y by N and then Z by O. + String replace_C_by_Z=A+B+Z+D+E+F+G+H+I+J; + String replace_A_by_Y=Y+B+C+D+E+F+G+H+I+J; + String replace_A_by_Z=Z+B+C+D+E+F+G+H+I+J; + String replace_J_by_Y=A+B+C+D+E+F+G+H+I+Y; + String replace_J_by_Z=A+B+C+D+E+F+G+H+I+Z; + String replace_BC_by_ZZ=A+Z+Z+D+E+F+G+H+I+J; + String replace_BCD_by_ZZZ=A+Z+Z+Z+E+F+G+H+I+J; + String replace_BD_by_ZZ=A+Z+C+Z+E+F+G+H+I+J; + String replace_BCDEGI_by_ZZZZZZ=A+Z+Z+Z+Z+F+Z+H+Z+J; + String replace_CEFGHJ_by_YYYYYY=A+B+Y+D+Y+Y+Y+Y+I+Y; + String replace_BDE_by_ZZY=A+Z+C+Z+Y+F+G+H+I+J; + + /** + * Check for a conflict where the second text was changed similar to the + * first one, but the second texts modification covers one more line. + * + * @throws IOException + */ + public void testTwoConflictingModifications() throws IOException { + assertEquals(A + XXX_0 + B + Z + XXX_1 + Z + Z + XXX_2 + D + E + F + G + + H + I + J, + merge(base, replace_C_by_Z, replace_BC_by_ZZ)); + } + + /** + * Test a case where we have three consecutive chunks. The first text + * modifies all three chunks. The second text modifies the first and the + * last chunk. This should be reported as one conflicting region. + * + * @throws IOException + */ + public void testOneAgainstTwoConflictingModifications() throws IOException { + assertEquals(A + XXX_0 + Z + Z + Z + XXX_1 + Z + C + Z + XXX_2 + E + F + + G + H + I + J, + merge(base, replace_BCD_by_ZZZ, replace_BD_by_ZZ)); + } + + /** + * Test a merge where only the second text contains modifications. Expect as + * merge result the second text. + * + * @throws IOException + */ + public void testNoAgainstOneModification() throws IOException { + assertEquals(replace_BD_by_ZZ.toString(), + merge(base, base, replace_BD_by_ZZ)); + } + + /** + * Both texts contain modifications but not on the same chunks. Expect a + * non-conflict merge result. + * + * @throws IOException + */ + public void testTwoNonConflictingModifications() throws IOException { + assertEquals(Y + B + Z + D + E + F + G + H + I + J, + merge(base, replace_C_by_Z, replace_A_by_Y)); + } + + /** + * Merge two complicated modifications. The merge algorithm has to extend + * and combine conflicting regions to get to the expected merge result. + * + * @throws IOException + */ + public void testTwoComplicatedModifications() throws IOException { + assertEquals(A + XXX_0 + Z + Z + Z + Z + F + Z + H + XXX_1 + B + Y + D + + Y + Y + Y + Y + XXX_2 + Z + Y, + merge(base, + replace_BCDEGI_by_ZZZZZZ, + replace_CEFGHJ_by_YYYYYY)); + } + + /** + * Test a conflicting region at the very start of the text. + * + * @throws IOException + */ + public void testConflictAtStart() throws IOException { + assertEquals(XXX_0 + Z + XXX_1 + Y + XXX_2 + B + C + D + E + F + G + H + + I + J, merge(base, replace_A_by_Z, replace_A_by_Y)); + } + + /** + * Test a conflicting region at the very end of the text. + * + * @throws IOException + */ + public void testConflictAtEnd() throws IOException { + assertEquals(A+B+C+D+E+F+G+H+I+XXX_0+Z+XXX_1+Y+XXX_2, merge(base, replace_J_by_Z, replace_J_by_Y)); + } + + private String merge(String commonBase, String ours, String theirs) throws IOException { + MergeResult r=MergeAlgorithm.merge(new RawText(Constants.encode(commonBase)), new RawText(Constants.encode(ours)), new RawText(Constants.encode(theirs))); + ByteArrayOutputStream bo=new ByteArrayOutputStream(50); + fmt.formatMerge(bo, r, "B", "O", "T", Constants.CHARACTER_ENCODING); + return new String(bo.toByteArray(), Constants.CHARACTER_ENCODING); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/CPUTimeStopWatch.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/CPUTimeStopWatch.java new file mode 100644 index 0000000000..55e51f710e --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/CPUTimeStopWatch.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2009, Christian Halstrick <christian.halstrick@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.util; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; + +/** + * A simple stopwatch which measures elapsed CPU time of the current thread. CPU + * time is the time spent on executing your own code plus the time spent on + * executing operating system calls triggered by your application. + * <p> + * This stopwatch needs a VM which supports getting CPU Time information for the + * current thread. The static method createInstance() will take care to return + * only a new instance of this class if the VM is capable of returning CPU time. + */ +public class CPUTimeStopWatch { + private long start; + + private static ThreadMXBean mxBean=ManagementFactory.getThreadMXBean(); + + /** + * use this method instead of the constructor to be sure that the underlying + * VM provides all features needed by this class. + * + * @return a new instance of {@link #CPUTimeStopWatch()} or + * <code>null</code> if the VM does not support getting CPU time + * information + */ + public static CPUTimeStopWatch createInstance() { + return mxBean.isCurrentThreadCpuTimeSupported() ? new CPUTimeStopWatch() + : null; + } + + /** + * Starts the stopwatch. If the stopwatch is already started this will + * restart the stopwatch. + */ + public void start() { + start = mxBean.getCurrentThreadCpuTime(); + } + + /** + * Stops the stopwatch and return the elapsed CPU time in nanoseconds. + * Should be called only on started stopwatches. + * + * @return the elapsed CPU time in nanoseconds. When called on non-started + * stopwatches (either because {@link #start()} was never called or + * {@link #stop()} was called after the last call to + * {@link #start()}) this method will return 0. + */ + public long stop() { + long cpuTime = readout(); + start = 0; + return cpuTime; + } + + /** + * Return the elapsed CPU time in nanoseconds. In contrast to + * {@link #stop()} the stopwatch will continue to run after this call. + * + * @return the elapsed CPU time in nanoseconds. When called on non-started + * stopwatches (either because {@link #start()} was never called or + * {@link #stop()} was called after the last call to + * {@link #start()}) this method will return 0. + */ + public long readout() { + return (start == 0) ? 0 : mxBean.getCurrentThreadCpuTime() - start; + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IntListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IntListTest.java index ecabeeea5b..b8d5bd1025 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IntListTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IntListTest.java @@ -150,6 +150,27 @@ public class IntListTest extends TestCase { } } + public void testSet() { + final IntList i = new IntList(); + i.add(1); + assertEquals(1, i.size()); + assertEquals(1, i.get(0)); + + i.set(0, 5); + assertEquals(5, i.get(0)); + + try { + i.set(5, 5); + fail("accepted set of 5 beyond end of list"); + } catch (ArrayIndexOutOfBoundsException e){ + assertTrue(true); + } + + i.set(1, 2); + assertEquals(2, i.size()); + assertEquals(2, i.get(1)); + } + public void testToString() { final IntList i = new IntList(); i.add(1); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java new file mode 100644 index 0000000000..2bcd134c66 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/UnionInputStreamTest.java @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2009, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.util.io; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Arrays; + +import junit.framework.TestCase; + +public class UnionInputStreamTest extends TestCase { + public void testEmptyStream() throws IOException { + final UnionInputStream u = new UnionInputStream(); + assertTrue(u.isEmpty()); + assertEquals(-1, u.read()); + assertEquals(-1, u.read(new byte[1], 0, 1)); + assertEquals(0, u.available()); + assertEquals(0, u.skip(1)); + u.close(); + } + + public void testReadSingleBytes() throws IOException { + final UnionInputStream u = new UnionInputStream(); + + assertTrue(u.isEmpty()); + u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 })); + u.add(new ByteArrayInputStream(new byte[] { 3 })); + u.add(new ByteArrayInputStream(new byte[] { 4, 5 })); + + assertFalse(u.isEmpty()); + assertEquals(3, u.available()); + assertEquals(1, u.read()); + assertEquals(0, u.read()); + assertEquals(2, u.read()); + assertEquals(0, u.available()); + + assertEquals(3, u.read()); + assertEquals(0, u.available()); + + assertEquals(4, u.read()); + assertEquals(1, u.available()); + assertEquals(5, u.read()); + assertEquals(0, u.available()); + assertEquals(-1, u.read()); + + assertTrue(u.isEmpty()); + u.add(new ByteArrayInputStream(new byte[] { (byte) 255 })); + assertEquals(255, u.read()); + assertEquals(-1, u.read()); + assertTrue(u.isEmpty()); + } + + public void testReadByteBlocks() throws IOException { + final UnionInputStream u = new UnionInputStream(); + u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 })); + u.add(new ByteArrayInputStream(new byte[] { 3 })); + u.add(new ByteArrayInputStream(new byte[] { 4, 5 })); + + final byte[] r = new byte[5]; + assertEquals(5, u.read(r, 0, 5)); + assertTrue(Arrays.equals(new byte[] { 1, 0, 2, 3, 4 }, r)); + assertEquals(1, u.read(r, 0, 5)); + assertEquals(5, r[0]); + assertEquals(-1, u.read(r, 0, 5)); + } + + public void testArrayConstructor() throws IOException { + final UnionInputStream u = new UnionInputStream( + new ByteArrayInputStream(new byte[] { 1, 0, 2 }), + new ByteArrayInputStream(new byte[] { 3 }), + new ByteArrayInputStream(new byte[] { 4, 5 })); + + final byte[] r = new byte[5]; + assertEquals(5, u.read(r, 0, 5)); + assertTrue(Arrays.equals(new byte[] { 1, 0, 2, 3, 4 }, r)); + assertEquals(1, u.read(r, 0, 5)); + assertEquals(5, r[0]); + assertEquals(-1, u.read(r, 0, 5)); + } + + public void testMarkSupported() { + final UnionInputStream u = new UnionInputStream(); + assertFalse(u.markSupported()); + u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 })); + assertFalse(u.markSupported()); + } + + public void testSkip() throws IOException { + final UnionInputStream u = new UnionInputStream(); + u.add(new ByteArrayInputStream(new byte[] { 1, 0, 2 })); + u.add(new ByteArrayInputStream(new byte[] { 3 })); + u.add(new ByteArrayInputStream(new byte[] { 4, 5 })); + assertEquals(0, u.skip(0)); + assertEquals(4, u.skip(4)); + assertEquals(4, u.read()); + assertEquals(1, u.skip(5)); + assertEquals(0, u.skip(5)); + assertEquals(-1, u.read()); + + u.add(new ByteArrayInputStream(new byte[] { 20, 30 }) { + public long skip(long n) { + return 0; + } + }); + assertEquals(2, u.skip(8)); + assertEquals(-1, u.read()); + } + + public void testAutoCloseDuringRead() throws IOException { + final UnionInputStream u = new UnionInputStream(); + final boolean closed[] = new boolean[2]; + u.add(new ByteArrayInputStream(new byte[] { 1 }) { + public void close() { + closed[0] = true; + } + }); + u.add(new ByteArrayInputStream(new byte[] { 2 }) { + public void close() { + closed[1] = true; + } + }); + + assertFalse(closed[0]); + assertFalse(closed[1]); + + assertEquals(1, u.read()); + assertFalse(closed[0]); + assertFalse(closed[1]); + + assertEquals(2, u.read()); + assertTrue(closed[0]); + assertFalse(closed[1]); + + assertEquals(-1, u.read()); + assertTrue(closed[0]); + assertTrue(closed[1]); + } + + public void testCloseDuringClose() throws IOException { + final UnionInputStream u = new UnionInputStream(); + final boolean closed[] = new boolean[2]; + u.add(new ByteArrayInputStream(new byte[] { 1 }) { + public void close() { + closed[0] = true; + } + }); + u.add(new ByteArrayInputStream(new byte[] { 2 }) { + public void close() { + closed[1] = true; + } + }); + + assertFalse(closed[0]); + assertFalse(closed[1]); + + u.close(); + + assertTrue(closed[0]); + assertTrue(closed[1]); + } + + public void testExceptionDuringClose() { + final UnionInputStream u = new UnionInputStream(); + u.add(new ByteArrayInputStream(new byte[] { 1 }) { + public void close() throws IOException { + throw new IOException("I AM A TEST"); + } + }); + try { + u.close(); + fail("close ignored inner stream exception"); + } catch (IOException e) { + assertEquals("I AM A TEST", e.getMessage()); + } + } +} |