You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

EGitPatchHistoryTest.java 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. /*
  2. * Copyright (C) 2008-2009, Google Inc.
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.patch;
  44. import static org.junit.Assert.assertEquals;
  45. import static org.junit.Assert.assertNotNull;
  46. import static org.junit.Assert.assertTrue;
  47. import static org.junit.Assert.fail;
  48. import java.io.BufferedReader;
  49. import java.io.IOException;
  50. import java.io.InputStreamReader;
  51. import java.io.UnsupportedEncodingException;
  52. import java.util.HashMap;
  53. import java.util.HashSet;
  54. import org.eclipse.jgit.lib.Constants;
  55. import org.eclipse.jgit.util.MutableInteger;
  56. import org.eclipse.jgit.util.RawParseUtils;
  57. import org.eclipse.jgit.util.TemporaryBuffer;
  58. import org.junit.Test;
  59. public class EGitPatchHistoryTest {
  60. @Test
  61. public void testParseHistory() throws Exception {
  62. final NumStatReader numstat = new NumStatReader();
  63. numstat.read();
  64. final HashMap<String, HashMap<String, StatInfo>> stats = numstat.stats;
  65. assertEquals(1211, stats.size());
  66. new PatchReader(stats).read();
  67. }
  68. static class StatInfo {
  69. int added, deleted;
  70. }
  71. static class PatchReader extends CommitReader {
  72. final HashSet<String> offBy1;
  73. final HashMap<String, HashMap<String, StatInfo>> stats;
  74. int errors;
  75. PatchReader(final HashMap<String, HashMap<String, StatInfo>> s)
  76. throws IOException {
  77. super(new String[] { "-p" });
  78. stats = s;
  79. offBy1 = new HashSet<>();
  80. offBy1.add("9bda5ece6806cd797416eaa47c7b927cc6e9c3b2");
  81. }
  82. @Override
  83. void onCommit(String cid, byte[] buf) {
  84. final HashMap<String, StatInfo> files = stats.remove(cid);
  85. assertNotNull("No files for " + cid, files);
  86. final Patch p = new Patch();
  87. p.parse(buf, 0, buf.length - 1);
  88. assertEquals("File count " + cid, files.size(), p.getFiles().size());
  89. if (!p.getErrors().isEmpty()) {
  90. for (final FormatError e : p.getErrors()) {
  91. System.out.println("error " + e.getMessage());
  92. System.out.println(" at " + e.getLineText());
  93. }
  94. dump(buf);
  95. fail("Unexpected error in " + cid);
  96. }
  97. for (final FileHeader fh : p.getFiles()) {
  98. final String fileName;
  99. if (fh.getChangeType() != FileHeader.ChangeType.DELETE)
  100. fileName = fh.getNewPath();
  101. else
  102. fileName = fh.getOldPath();
  103. final StatInfo s = files.remove(fileName);
  104. final String nid = fileName + " in " + cid;
  105. assertNotNull("No " + nid, s);
  106. int added = 0, deleted = 0;
  107. for (final HunkHeader h : fh.getHunks()) {
  108. added += h.getOldImage().getLinesAdded();
  109. deleted += h.getOldImage().getLinesDeleted();
  110. }
  111. if (s.added == added) {
  112. //
  113. } else if (s.added == added + 1 && offBy1.contains(cid)) {
  114. //
  115. } else {
  116. dump(buf);
  117. assertEquals("Added diff in " + nid, s.added, added);
  118. }
  119. if (s.deleted == deleted) {
  120. //
  121. } else if (s.deleted == deleted + 1 && offBy1.contains(cid)) {
  122. //
  123. } else {
  124. dump(buf);
  125. assertEquals("Deleted diff in " + nid, s.deleted, deleted);
  126. }
  127. }
  128. assertTrue("Missed files in " + cid, files.isEmpty());
  129. }
  130. private static void dump(final byte[] buf) {
  131. String str;
  132. try {
  133. str = new String(buf, 0, buf.length - 1, "ISO-8859-1");
  134. } catch (UnsupportedEncodingException e) {
  135. throw new RuntimeException(e);
  136. }
  137. System.out.println("<<" + str + ">>");
  138. }
  139. }
  140. static class NumStatReader extends CommitReader {
  141. final HashMap<String, HashMap<String, StatInfo>> stats = new HashMap<>();
  142. NumStatReader() throws IOException {
  143. super(new String[] { "--numstat" });
  144. }
  145. @Override
  146. void onCommit(String commitId, byte[] buf) {
  147. final HashMap<String, StatInfo> files = new HashMap<>();
  148. final MutableInteger ptr = new MutableInteger();
  149. while (ptr.value < buf.length) {
  150. if (buf[ptr.value] == '\n')
  151. break;
  152. final StatInfo i = new StatInfo();
  153. i.added = RawParseUtils.parseBase10(buf, ptr.value, ptr);
  154. i.deleted = RawParseUtils.parseBase10(buf, ptr.value + 1, ptr);
  155. final int eol = RawParseUtils.nextLF(buf, ptr.value);
  156. final String name = RawParseUtils.decode(Constants.CHARSET,
  157. buf, ptr.value + 1, eol - 1);
  158. files.put(name, i);
  159. ptr.value = eol;
  160. }
  161. stats.put(commitId, files);
  162. }
  163. }
  164. static abstract class CommitReader {
  165. private Process proc;
  166. CommitReader(final String[] args) throws IOException {
  167. final String[] realArgs = new String[3 + args.length + 1];
  168. realArgs[0] = "git";
  169. realArgs[1] = "log";
  170. realArgs[2] = "--pretty=format:commit %H";
  171. System.arraycopy(args, 0, realArgs, 3, args.length);
  172. realArgs[3 + args.length] = "a4b98ed15ea5f165a7aa0f2fd2ea6fcce6710925";
  173. proc = Runtime.getRuntime().exec(realArgs);
  174. proc.getOutputStream().close();
  175. proc.getErrorStream().close();
  176. }
  177. void read() throws IOException, InterruptedException {
  178. final BufferedReader in = new BufferedReader(new InputStreamReader(
  179. proc.getInputStream(), "ISO-8859-1"));
  180. String commitId = null;
  181. TemporaryBuffer buf = null;
  182. for (;;) {
  183. String line = in.readLine();
  184. if (line == null)
  185. break;
  186. if (line.startsWith("commit ")) {
  187. if (buf != null) {
  188. buf.close();
  189. onCommit(commitId, buf.toByteArray());
  190. buf.destroy();
  191. }
  192. commitId = line.substring("commit ".length());
  193. buf = new TemporaryBuffer.LocalFile(null);
  194. } else if (buf != null) {
  195. buf.write(line.getBytes("ISO-8859-1"));
  196. buf.write('\n');
  197. }
  198. }
  199. in.close();
  200. assertEquals(0, proc.waitFor());
  201. proc = null;
  202. }
  203. abstract void onCommit(String commitId, byte[] buf);
  204. }
  205. }