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.

CanonicalTreeParserTest.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  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.treewalk;
  44. import static java.nio.charset.StandardCharsets.UTF_8;
  45. import static org.eclipse.jgit.lib.FileMode.REGULAR_FILE;
  46. import static org.eclipse.jgit.lib.FileMode.SYMLINK;
  47. import static org.junit.Assert.assertEquals;
  48. import static org.junit.Assert.assertFalse;
  49. import static org.junit.Assert.assertSame;
  50. import static org.junit.Assert.assertTrue;
  51. import java.io.ByteArrayOutputStream;
  52. import org.eclipse.jgit.errors.CorruptObjectException;
  53. import org.eclipse.jgit.lib.Constants;
  54. import org.eclipse.jgit.lib.FileMode;
  55. import org.eclipse.jgit.lib.ObjectId;
  56. import org.eclipse.jgit.lib.TreeFormatter;
  57. import org.eclipse.jgit.util.RawParseUtils;
  58. import org.junit.Before;
  59. import org.junit.Test;
  60. public class CanonicalTreeParserTest {
  61. private final CanonicalTreeParser ctp = new CanonicalTreeParser();
  62. private final FileMode m644 = FileMode.REGULAR_FILE;
  63. private final FileMode mt = FileMode.TREE;
  64. private final ObjectId hash_a = ObjectId
  65. .fromString("6b9c715d21d5486e59083fb6071566aa6ecd4d42");
  66. private final ObjectId hash_foo = ObjectId
  67. .fromString("a213e8e25bb2442326e86cbfb9ef56319f482869");
  68. private final ObjectId hash_sometree = ObjectId
  69. .fromString("daf4bdb0d7bb24319810fe0e73aa317663448c93");
  70. private byte[] tree1;
  71. private byte[] tree2;
  72. private byte[] tree3;
  73. @Before
  74. public void setUp() throws Exception {
  75. tree1 = mktree(entry(m644, "a", hash_a));
  76. tree2 = mktree(entry(m644, "a", hash_a), entry(m644, "foo", hash_foo));
  77. tree3 = mktree(entry(m644, "a", hash_a), entry(mt, "b_sometree",
  78. hash_sometree), entry(m644, "foo", hash_foo));
  79. }
  80. private static byte[] mktree(byte[]... data) throws Exception {
  81. final ByteArrayOutputStream out = new ByteArrayOutputStream();
  82. for (byte[] e : data)
  83. out.write(e);
  84. return out.toByteArray();
  85. }
  86. private static byte[] entry(final FileMode mode, final String name,
  87. final ObjectId id) throws Exception {
  88. final ByteArrayOutputStream out = new ByteArrayOutputStream();
  89. mode.copyTo(out);
  90. out.write(' ');
  91. out.write(Constants.encode(name));
  92. out.write(0);
  93. id.copyRawTo(out);
  94. return out.toByteArray();
  95. }
  96. private String path() {
  97. return RawParseUtils.decode(UTF_8, ctp.path,
  98. ctp.pathOffset, ctp.pathLen);
  99. }
  100. @Test
  101. public void testEmptyTree_AtEOF() throws Exception {
  102. ctp.reset(new byte[0]);
  103. assertTrue(ctp.eof());
  104. }
  105. @Test
  106. public void testOneEntry_Forward() throws Exception {
  107. ctp.reset(tree1);
  108. assertTrue(ctp.first());
  109. assertFalse(ctp.eof());
  110. assertEquals(m644.getBits(), ctp.mode);
  111. assertEquals("a", path());
  112. assertEquals(hash_a, ctp.getEntryObjectId());
  113. ctp.next(1);
  114. assertFalse(ctp.first());
  115. assertTrue(ctp.eof());
  116. }
  117. @Test
  118. public void testTwoEntries_ForwardOneAtATime() throws Exception {
  119. ctp.reset(tree2);
  120. assertTrue(ctp.first());
  121. assertFalse(ctp.eof());
  122. assertEquals(m644.getBits(), ctp.mode);
  123. assertEquals("a", path());
  124. assertEquals(hash_a, ctp.getEntryObjectId());
  125. ctp.next(1);
  126. assertFalse(ctp.eof());
  127. assertEquals(m644.getBits(), ctp.mode);
  128. assertEquals("foo", path());
  129. assertEquals(hash_foo, ctp.getEntryObjectId());
  130. ctp.next(1);
  131. assertFalse(ctp.first());
  132. assertTrue(ctp.eof());
  133. }
  134. @Test
  135. public void testOneEntry_Seek1IsEOF() throws Exception {
  136. ctp.reset(tree1);
  137. ctp.next(1);
  138. assertTrue(ctp.eof());
  139. }
  140. @Test
  141. public void testTwoEntries_Seek2IsEOF() throws Exception {
  142. ctp.reset(tree2);
  143. ctp.next(2);
  144. assertTrue(ctp.eof());
  145. }
  146. @Test
  147. public void testThreeEntries_Seek3IsEOF() throws Exception {
  148. ctp.reset(tree3);
  149. ctp.next(3);
  150. assertTrue(ctp.eof());
  151. }
  152. @Test
  153. public void testThreeEntries_Seek2() throws Exception {
  154. ctp.reset(tree3);
  155. ctp.next(2);
  156. assertFalse(ctp.eof());
  157. assertFalse(ctp.eof());
  158. assertEquals(m644.getBits(), ctp.mode);
  159. assertEquals("foo", path());
  160. assertEquals(hash_foo, ctp.getEntryObjectId());
  161. ctp.next(1);
  162. assertTrue(ctp.eof());
  163. }
  164. @Test
  165. public void testOneEntry_Backwards() throws Exception {
  166. ctp.reset(tree1);
  167. ctp.next(1);
  168. assertFalse(ctp.first());
  169. assertTrue(ctp.eof());
  170. ctp.back(1);
  171. assertTrue(ctp.first());
  172. assertFalse(ctp.eof());
  173. assertEquals(m644.getBits(), ctp.mode);
  174. assertEquals("a", path());
  175. assertEquals(hash_a, ctp.getEntryObjectId());
  176. }
  177. @Test
  178. public void testTwoEntries_BackwardsOneAtATime() throws Exception {
  179. ctp.reset(tree2);
  180. ctp.next(2);
  181. assertTrue(ctp.eof());
  182. ctp.back(1);
  183. assertFalse(ctp.eof());
  184. assertEquals(m644.getBits(), ctp.mode);
  185. assertEquals("foo", path());
  186. assertEquals(hash_foo, ctp.getEntryObjectId());
  187. ctp.back(1);
  188. assertFalse(ctp.eof());
  189. assertEquals(m644.getBits(), ctp.mode);
  190. assertEquals("a", path());
  191. assertEquals(hash_a, ctp.getEntryObjectId());
  192. }
  193. @Test
  194. public void testTwoEntries_BackwardsTwo() throws Exception {
  195. ctp.reset(tree2);
  196. ctp.next(2);
  197. assertTrue(ctp.eof());
  198. ctp.back(2);
  199. assertFalse(ctp.eof());
  200. assertEquals(m644.getBits(), ctp.mode);
  201. assertEquals("a", path());
  202. assertEquals(hash_a, ctp.getEntryObjectId());
  203. ctp.next(1);
  204. assertFalse(ctp.eof());
  205. assertEquals(m644.getBits(), ctp.mode);
  206. assertEquals("foo", path());
  207. assertEquals(hash_foo, ctp.getEntryObjectId());
  208. ctp.next(1);
  209. assertTrue(ctp.eof());
  210. }
  211. @Test
  212. public void testThreeEntries_BackwardsTwo() throws Exception {
  213. ctp.reset(tree3);
  214. ctp.next(3);
  215. assertTrue(ctp.eof());
  216. ctp.back(2);
  217. assertFalse(ctp.eof());
  218. assertEquals(mt.getBits(), ctp.mode);
  219. assertEquals("b_sometree", path());
  220. assertEquals(hash_sometree, ctp.getEntryObjectId());
  221. ctp.next(1);
  222. assertFalse(ctp.eof());
  223. assertEquals(m644.getBits(), ctp.mode);
  224. assertEquals("foo", path());
  225. assertEquals(hash_foo, ctp.getEntryObjectId());
  226. ctp.next(1);
  227. assertTrue(ctp.eof());
  228. }
  229. @Test
  230. public void testBackwards_ConfusingPathName() throws Exception {
  231. final String aVeryConfusingName = "confusing 644 entry 755 and others";
  232. ctp.reset(mktree(entry(m644, "a", hash_a), entry(mt, aVeryConfusingName,
  233. hash_sometree), entry(m644, "foo", hash_foo)));
  234. ctp.next(3);
  235. assertTrue(ctp.eof());
  236. ctp.back(2);
  237. assertFalse(ctp.eof());
  238. assertEquals(mt.getBits(), ctp.mode);
  239. assertEquals(aVeryConfusingName, path());
  240. assertEquals(hash_sometree, ctp.getEntryObjectId());
  241. ctp.back(1);
  242. assertFalse(ctp.eof());
  243. assertEquals(m644.getBits(), ctp.mode);
  244. assertEquals("a", path());
  245. assertEquals(hash_a, ctp.getEntryObjectId());
  246. }
  247. @Test
  248. public void testBackwords_Prebuilts1() throws Exception {
  249. // What is interesting about this test is the ObjectId for the
  250. // "darwin-x86" path entry ends in an octal digit (37 == '7').
  251. // Thus when scanning backwards we could over scan and consume
  252. // part of the SHA-1, and miss the path terminator.
  253. //
  254. final ObjectId common = ObjectId
  255. .fromString("af7bf97cb9bce3f60f1d651a0ef862e9447dd8bc");
  256. final ObjectId darwinx86 = ObjectId
  257. .fromString("e927f7398240f78face99e1a738dac54ef738e37");
  258. final ObjectId linuxx86 = ObjectId
  259. .fromString("ac08dd97120c7cb7d06e98cd5b152011183baf21");
  260. final ObjectId windows = ObjectId
  261. .fromString("6c4c64c221a022bb973165192cca4812033479df");
  262. ctp.reset(mktree(entry(mt, "common", common), entry(mt, "darwin-x86",
  263. darwinx86), entry(mt, "linux-x86", linuxx86), entry(mt,
  264. "windows", windows)));
  265. ctp.next(3);
  266. assertEquals("windows", ctp.getEntryPathString());
  267. assertSame(mt, ctp.getEntryFileMode());
  268. assertEquals(windows, ctp.getEntryObjectId());
  269. ctp.back(1);
  270. assertEquals("linux-x86", ctp.getEntryPathString());
  271. assertSame(mt, ctp.getEntryFileMode());
  272. assertEquals(linuxx86, ctp.getEntryObjectId());
  273. ctp.next(1);
  274. assertEquals("windows", ctp.getEntryPathString());
  275. assertSame(mt, ctp.getEntryFileMode());
  276. assertEquals(windows, ctp.getEntryObjectId());
  277. }
  278. @Test
  279. public void testBackwords_Prebuilts2() throws Exception {
  280. // What is interesting about this test is the ObjectId for the
  281. // "darwin-x86" path entry ends in an octal digit (37 == '7').
  282. // Thus when scanning backwards we could over scan and consume
  283. // part of the SHA-1, and miss the path terminator.
  284. //
  285. final ObjectId common = ObjectId
  286. .fromString("af7bf97cb9bce3f60f1d651a0ef862e9447dd8bc");
  287. final ObjectId darwinx86 = ObjectId
  288. .fromString("0000000000000000000000000000000000000037");
  289. final ObjectId linuxx86 = ObjectId
  290. .fromString("ac08dd97120c7cb7d06e98cd5b152011183baf21");
  291. final ObjectId windows = ObjectId
  292. .fromString("6c4c64c221a022bb973165192cca4812033479df");
  293. ctp.reset(mktree(entry(mt, "common", common), entry(mt, "darwin-x86",
  294. darwinx86), entry(mt, "linux-x86", linuxx86), entry(mt,
  295. "windows", windows)));
  296. ctp.next(3);
  297. assertEquals("windows", ctp.getEntryPathString());
  298. assertSame(mt, ctp.getEntryFileMode());
  299. assertEquals(windows, ctp.getEntryObjectId());
  300. ctp.back(1);
  301. assertEquals("linux-x86", ctp.getEntryPathString());
  302. assertSame(mt, ctp.getEntryFileMode());
  303. assertEquals(linuxx86, ctp.getEntryObjectId());
  304. ctp.next(1);
  305. assertEquals("windows", ctp.getEntryPathString());
  306. assertSame(mt, ctp.getEntryFileMode());
  307. assertEquals(windows, ctp.getEntryObjectId());
  308. }
  309. @Test
  310. public void testFreakingHugePathName() throws Exception {
  311. final int n = AbstractTreeIterator.DEFAULT_PATH_SIZE * 4;
  312. final StringBuilder b = new StringBuilder(n);
  313. for (int i = 0; i < n; i++)
  314. b.append('q');
  315. final String name = b.toString();
  316. ctp.reset(entry(m644, name, hash_a));
  317. assertFalse(ctp.eof());
  318. assertEquals(name, RawParseUtils.decode(UTF_8, ctp.path,
  319. ctp.pathOffset, ctp.pathLen));
  320. }
  321. @Test
  322. public void testFindAttributesWhenFirst() throws CorruptObjectException {
  323. TreeFormatter tree = new TreeFormatter();
  324. tree.append(".gitattributes", REGULAR_FILE, hash_a);
  325. ctp.reset(tree.toByteArray());
  326. assertTrue(ctp.findFile(".gitattributes"));
  327. assertEquals(REGULAR_FILE.getBits(), ctp.getEntryRawMode());
  328. assertEquals(".gitattributes", ctp.getEntryPathString());
  329. assertEquals(hash_a, ctp.getEntryObjectId());
  330. }
  331. @Test
  332. public void testFindAttributesWhenSecond() throws CorruptObjectException {
  333. TreeFormatter tree = new TreeFormatter();
  334. tree.append(".config", SYMLINK, hash_a);
  335. tree.append(".gitattributes", REGULAR_FILE, hash_foo);
  336. ctp.reset(tree.toByteArray());
  337. assertTrue(ctp.findFile(".gitattributes"));
  338. assertEquals(REGULAR_FILE.getBits(), ctp.getEntryRawMode());
  339. assertEquals(".gitattributes", ctp.getEntryPathString());
  340. assertEquals(hash_foo, ctp.getEntryObjectId());
  341. }
  342. @Test
  343. public void testFindAttributesWhenMissing() throws CorruptObjectException {
  344. TreeFormatter tree = new TreeFormatter();
  345. tree.append("src", REGULAR_FILE, hash_a);
  346. tree.append("zoo", REGULAR_FILE, hash_foo);
  347. ctp.reset(tree.toByteArray());
  348. assertFalse(ctp.findFile(".gitattributes"));
  349. assertEquals(11, ctp.idOffset()); // Did not walk the entire tree.
  350. assertEquals("src", ctp.getEntryPathString());
  351. }
  352. }