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.

ObjectCheckerTest.java 49KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727
  1. /*
  2. * Copyright (C) 2008-2010, Google Inc.
  3. * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
  4. * and other copyright owners as documented in the project's IP log.
  5. *
  6. * This program and the accompanying materials are made available
  7. * under the terms of the Eclipse Distribution License v1.0 which
  8. * accompanies this distribution, is reproduced below, and is
  9. * available at http://www.eclipse.org/org/documents/edl-v10.php
  10. *
  11. * All rights reserved.
  12. *
  13. * Redistribution and use in source and binary forms, with or
  14. * without modification, are permitted provided that the following
  15. * conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright
  18. * notice, this list of conditions and the following disclaimer.
  19. *
  20. * - Redistributions in binary form must reproduce the above
  21. * copyright notice, this list of conditions and the following
  22. * disclaimer in the documentation and/or other materials provided
  23. * with the distribution.
  24. *
  25. * - Neither the name of the Eclipse Foundation, Inc. nor the
  26. * names of its contributors may be used to endorse or promote
  27. * products derived from this software without specific prior
  28. * written permission.
  29. *
  30. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  31. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  32. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  33. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  34. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  35. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  39. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  42. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  43. */
  44. package org.eclipse.jgit.lib;
  45. import static java.lang.Integer.valueOf;
  46. import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
  47. import static org.eclipse.jgit.lib.Constants.OBJ_BAD;
  48. import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
  49. import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
  50. import static org.eclipse.jgit.lib.Constants.OBJ_TAG;
  51. import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
  52. import static org.eclipse.jgit.lib.Constants.encode;
  53. import static org.eclipse.jgit.lib.Constants.encodeASCII;
  54. import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.DUPLICATE_ENTRIES;
  55. import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.EMPTY_NAME;
  56. import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.FULL_PATHNAME;
  57. import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOT;
  58. import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOTDOT;
  59. import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.HAS_DOTGIT;
  60. import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.NULL_SHA1;
  61. import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.TREE_NOT_SORTED;
  62. import static org.eclipse.jgit.lib.ObjectChecker.ErrorType.ZERO_PADDED_FILEMODE;
  63. import static org.junit.Assert.assertEquals;
  64. import static org.junit.Assert.assertSame;
  65. import static org.junit.Assert.fail;
  66. import java.io.UnsupportedEncodingException;
  67. import java.text.MessageFormat;
  68. import org.eclipse.jgit.errors.CorruptObjectException;
  69. import org.eclipse.jgit.internal.JGitText;
  70. import org.junit.Before;
  71. import org.junit.Test;
  72. public class ObjectCheckerTest {
  73. private ObjectChecker checker;
  74. @Before
  75. public void setUp() throws Exception {
  76. checker = new ObjectChecker();
  77. }
  78. @Test
  79. public void testInvalidType() {
  80. String msg = MessageFormat.format(
  81. JGitText.get().corruptObjectInvalidType2,
  82. valueOf(OBJ_BAD));
  83. assertCorrupt(msg, OBJ_BAD, new byte[0]);
  84. }
  85. @Test
  86. public void testCheckBlob() throws CorruptObjectException {
  87. // Any blob should pass...
  88. checker.checkBlob(new byte[0]);
  89. checker.checkBlob(new byte[1]);
  90. checker.check(OBJ_BLOB, new byte[0]);
  91. checker.check(OBJ_BLOB, new byte[1]);
  92. }
  93. @Test
  94. public void testValidCommitNoParent() throws CorruptObjectException {
  95. StringBuilder b = new StringBuilder();
  96. b.append("tree ");
  97. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  98. b.append('\n');
  99. b.append("author A. U. Thor <author@localhost> 1 +0000\n");
  100. b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
  101. byte[] data = encodeASCII(b.toString());
  102. checker.checkCommit(data);
  103. checker.check(OBJ_COMMIT, data);
  104. }
  105. @Test
  106. public void testValidCommitBlankAuthor() throws CorruptObjectException {
  107. StringBuilder b = new StringBuilder();
  108. b.append("tree ");
  109. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  110. b.append('\n');
  111. b.append("author <> 0 +0000\n");
  112. b.append("committer <> 0 +0000\n");
  113. byte[] data = encodeASCII(b.toString());
  114. checker.checkCommit(data);
  115. checker.check(OBJ_COMMIT, data);
  116. }
  117. @Test
  118. public void testCommitCorruptAuthor() throws CorruptObjectException {
  119. StringBuilder b = new StringBuilder();
  120. b.append("tree be9bfa841874ccc9f2ef7c48d0c76226f89b7189\n");
  121. b.append("author b <b@c> <b@c> 0 +0000\n");
  122. b.append("committer <> 0 +0000\n");
  123. byte[] data = encodeASCII(b.toString());
  124. assertCorrupt("bad date", OBJ_COMMIT, data);
  125. checker.setAllowInvalidPersonIdent(true);
  126. checker.checkCommit(data);
  127. checker.setAllowInvalidPersonIdent(false);
  128. assertSkipListAccepts(OBJ_COMMIT, data);
  129. }
  130. @Test
  131. public void testCommitCorruptCommitter() throws CorruptObjectException {
  132. StringBuilder b = new StringBuilder();
  133. b.append("tree be9bfa841874ccc9f2ef7c48d0c76226f89b7189\n");
  134. b.append("author <> 0 +0000\n");
  135. b.append("committer b <b@c> <b@c> 0 +0000\n");
  136. byte[] data = encodeASCII(b.toString());
  137. assertCorrupt("bad date", OBJ_COMMIT, data);
  138. checker.setAllowInvalidPersonIdent(true);
  139. checker.checkCommit(data);
  140. checker.setAllowInvalidPersonIdent(false);
  141. assertSkipListAccepts(OBJ_COMMIT, data);
  142. }
  143. @Test
  144. public void testValidCommit1Parent() throws CorruptObjectException {
  145. StringBuilder b = new StringBuilder();
  146. b.append("tree ");
  147. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  148. b.append('\n');
  149. b.append("parent ");
  150. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  151. b.append('\n');
  152. b.append("author A. U. Thor <author@localhost> 1 +0000\n");
  153. b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
  154. byte[] data = encodeASCII(b.toString());
  155. checker.checkCommit(data);
  156. checker.check(OBJ_COMMIT, data);
  157. }
  158. @Test
  159. public void testValidCommit2Parent() throws CorruptObjectException {
  160. StringBuilder b = new StringBuilder();
  161. b.append("tree ");
  162. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  163. b.append('\n');
  164. b.append("parent ");
  165. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  166. b.append('\n');
  167. b.append("parent ");
  168. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  169. b.append('\n');
  170. b.append("author A. U. Thor <author@localhost> 1 +0000\n");
  171. b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
  172. byte[] data = encodeASCII(b.toString());
  173. checker.checkCommit(data);
  174. checker.check(OBJ_COMMIT, data);
  175. }
  176. @Test
  177. public void testValidCommit128Parent() throws CorruptObjectException {
  178. StringBuilder b = new StringBuilder();
  179. b.append("tree ");
  180. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  181. b.append('\n');
  182. for (int i = 0; i < 128; i++) {
  183. b.append("parent ");
  184. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  185. b.append('\n');
  186. }
  187. b.append("author A. U. Thor <author@localhost> 1 +0000\n");
  188. b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
  189. byte[] data = encodeASCII(b.toString());
  190. checker.checkCommit(data);
  191. checker.check(OBJ_COMMIT, data);
  192. }
  193. @Test
  194. public void testValidCommitNormalTime() throws CorruptObjectException {
  195. StringBuilder b = new StringBuilder();
  196. String when = "1222757360 -0730";
  197. b.append("tree ");
  198. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  199. b.append('\n');
  200. b.append("author A. U. Thor <author@localhost> " + when + "\n");
  201. b.append("committer A. U. Thor <author@localhost> " + when + "\n");
  202. byte[] data = encodeASCII(b.toString());
  203. checker.checkCommit(data);
  204. checker.check(OBJ_COMMIT, data);
  205. }
  206. @Test
  207. public void testInvalidCommitNoTree1() {
  208. StringBuilder b = new StringBuilder();
  209. b.append("parent ");
  210. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  211. b.append('\n');
  212. assertCorrupt("no tree header", OBJ_COMMIT, b);
  213. }
  214. @Test
  215. public void testInvalidCommitNoTree2() {
  216. StringBuilder b = new StringBuilder();
  217. b.append("trie ");
  218. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  219. b.append('\n');
  220. assertCorrupt("no tree header", OBJ_COMMIT, b);
  221. }
  222. @Test
  223. public void testInvalidCommitNoTree3() {
  224. StringBuilder b = new StringBuilder();
  225. b.append("tree");
  226. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  227. b.append('\n');
  228. assertCorrupt("no tree header", OBJ_COMMIT, b);
  229. }
  230. @Test
  231. public void testInvalidCommitNoTree4() {
  232. StringBuilder b = new StringBuilder();
  233. b.append("tree\t");
  234. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  235. b.append('\n');
  236. assertCorrupt("no tree header", OBJ_COMMIT, b);
  237. }
  238. @Test
  239. public void testInvalidCommitInvalidTree1() {
  240. StringBuilder b = new StringBuilder();
  241. b.append("tree ");
  242. b.append("zzzzfa841874ccc9f2ef7c48d0c76226f89b7189");
  243. b.append('\n');
  244. assertCorrupt("invalid tree", OBJ_COMMIT, b);
  245. }
  246. @Test
  247. public void testInvalidCommitInvalidTree2() {
  248. StringBuilder b = new StringBuilder();
  249. b.append("tree ");
  250. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  251. b.append("z\n");
  252. assertCorrupt("invalid tree", OBJ_COMMIT, b);
  253. }
  254. @Test
  255. public void testInvalidCommitInvalidTree3() {
  256. StringBuilder b = new StringBuilder();
  257. b.append("tree ");
  258. b.append("be9b");
  259. b.append("\n");
  260. byte[] data = encodeASCII(b.toString());
  261. assertCorrupt("invalid tree", OBJ_COMMIT, data);
  262. }
  263. @Test
  264. public void testInvalidCommitInvalidTree4() {
  265. StringBuilder b = new StringBuilder();
  266. b.append("tree ");
  267. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  268. b.append('\n');
  269. assertCorrupt("invalid tree", OBJ_COMMIT, b);
  270. }
  271. @Test
  272. public void testInvalidCommitInvalidParent1() {
  273. StringBuilder b = new StringBuilder();
  274. b.append("tree ");
  275. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  276. b.append('\n');
  277. b.append("parent ");
  278. b.append("\n");
  279. assertCorrupt("invalid parent", OBJ_COMMIT, b);
  280. }
  281. @Test
  282. public void testInvalidCommitInvalidParent2() {
  283. StringBuilder b = new StringBuilder();
  284. b.append("tree ");
  285. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  286. b.append('\n');
  287. b.append("parent ");
  288. b.append("zzzzfa841874ccc9f2ef7c48d0c76226f89b7189");
  289. b.append("\n");
  290. assertCorrupt("invalid parent", OBJ_COMMIT, b);
  291. }
  292. @Test
  293. public void testInvalidCommitInvalidParent3() {
  294. StringBuilder b = new StringBuilder();
  295. b.append("tree ");
  296. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  297. b.append('\n');
  298. b.append("parent ");
  299. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  300. b.append("\n");
  301. assertCorrupt("invalid parent", OBJ_COMMIT, b);
  302. }
  303. @Test
  304. public void testInvalidCommitInvalidParent4() {
  305. StringBuilder b = new StringBuilder();
  306. b.append("tree ");
  307. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  308. b.append('\n');
  309. b.append("parent ");
  310. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  311. b.append("z\n");
  312. assertCorrupt("invalid parent", OBJ_COMMIT, b);
  313. }
  314. @Test
  315. public void testInvalidCommitInvalidParent5() {
  316. StringBuilder b = new StringBuilder();
  317. b.append("tree ");
  318. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  319. b.append('\n');
  320. b.append("parent\t");
  321. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  322. b.append("\n");
  323. byte[] data = encodeASCII(b.toString());
  324. // Yes, really, we complain about author not being
  325. // found as the invalid parent line wasn't consumed.
  326. assertCorrupt("no author", OBJ_COMMIT, data);
  327. }
  328. @Test
  329. public void testInvalidCommitNoAuthor() throws CorruptObjectException {
  330. StringBuilder b = new StringBuilder();
  331. b.append("tree ");
  332. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  333. b.append('\n');
  334. b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
  335. byte[] data = encodeASCII(b.toString());
  336. assertCorrupt("no author", OBJ_COMMIT, data);
  337. assertSkipListAccepts(OBJ_COMMIT, data);
  338. }
  339. @Test
  340. public void testInvalidCommitNoCommitter1() throws CorruptObjectException {
  341. StringBuilder b = new StringBuilder();
  342. b.append("tree ");
  343. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  344. b.append('\n');
  345. b.append("author A. U. Thor <author@localhost> 1 +0000\n");
  346. byte[] data = encodeASCII(b.toString());
  347. assertCorrupt("no committer", OBJ_COMMIT, data);
  348. assertSkipListAccepts(OBJ_COMMIT, data);
  349. }
  350. @Test
  351. public void testInvalidCommitNoCommitter2() throws CorruptObjectException {
  352. StringBuilder b = new StringBuilder();
  353. b.append("tree ");
  354. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  355. b.append('\n');
  356. b.append("author A. U. Thor <author@localhost> 1 +0000\n");
  357. b.append("\n");
  358. byte[] data = encodeASCII(b.toString());
  359. assertCorrupt("no committer", OBJ_COMMIT, data);
  360. assertSkipListAccepts(OBJ_COMMIT, data);
  361. }
  362. @Test
  363. public void testInvalidCommitInvalidAuthor1()
  364. throws CorruptObjectException {
  365. StringBuilder b = new StringBuilder();
  366. b.append("tree ");
  367. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  368. b.append('\n');
  369. b.append("author A. U. Thor <foo 1 +0000\n");
  370. byte[] data = encodeASCII(b.toString());
  371. assertCorrupt("bad email", OBJ_COMMIT, data);
  372. assertSkipListAccepts(OBJ_COMMIT, data);
  373. }
  374. @Test
  375. public void testInvalidCommitInvalidAuthor2()
  376. throws CorruptObjectException {
  377. StringBuilder b = new StringBuilder();
  378. b.append("tree ");
  379. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  380. b.append('\n');
  381. b.append("author A. U. Thor foo> 1 +0000\n");
  382. byte[] data = encodeASCII(b.toString());
  383. assertCorrupt("missing email", OBJ_COMMIT, data);
  384. assertSkipListAccepts(OBJ_COMMIT, data);
  385. }
  386. @Test
  387. public void testInvalidCommitInvalidAuthor3()
  388. throws CorruptObjectException {
  389. StringBuilder b = new StringBuilder();
  390. b.append("tree ");
  391. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  392. b.append('\n');
  393. b.append("author 1 +0000\n");
  394. byte[] data = encodeASCII(b.toString());
  395. assertCorrupt("missing email", OBJ_COMMIT, data);
  396. assertSkipListAccepts(OBJ_COMMIT, data);
  397. }
  398. @Test
  399. public void testInvalidCommitInvalidAuthor4()
  400. throws CorruptObjectException {
  401. StringBuilder b = new StringBuilder();
  402. b.append("tree ");
  403. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  404. b.append('\n');
  405. b.append("author a <b> +0000\n");
  406. byte[] data = encodeASCII(b.toString());
  407. assertCorrupt("bad date", OBJ_COMMIT, data);
  408. assertSkipListAccepts(OBJ_COMMIT, data);
  409. }
  410. @Test
  411. public void testInvalidCommitInvalidAuthor5()
  412. throws CorruptObjectException {
  413. StringBuilder b = new StringBuilder();
  414. b.append("tree ");
  415. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  416. b.append('\n');
  417. b.append("author a <b>\n");
  418. byte[] data = encodeASCII(b.toString());
  419. assertCorrupt("bad date", OBJ_COMMIT, data);
  420. assertSkipListAccepts(OBJ_COMMIT, data);
  421. }
  422. @Test
  423. public void testInvalidCommitInvalidAuthor6()
  424. throws CorruptObjectException {
  425. StringBuilder b = new StringBuilder();
  426. b.append("tree ");
  427. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  428. b.append('\n');
  429. b.append("author a <b> z");
  430. byte[] data = encodeASCII(b.toString());
  431. assertCorrupt("bad date", OBJ_COMMIT, data);
  432. assertSkipListAccepts(OBJ_COMMIT, data);
  433. }
  434. @Test
  435. public void testInvalidCommitInvalidAuthor7()
  436. throws CorruptObjectException {
  437. StringBuilder b = new StringBuilder();
  438. b.append("tree ");
  439. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  440. b.append('\n');
  441. b.append("author a <b> 1 z");
  442. byte[] data = encodeASCII(b.toString());
  443. assertCorrupt("bad time zone", OBJ_COMMIT, data);
  444. assertSkipListAccepts(OBJ_COMMIT, data);
  445. }
  446. @Test
  447. public void testInvalidCommitInvalidCommitter()
  448. throws CorruptObjectException {
  449. StringBuilder b = new StringBuilder();
  450. b.append("tree ");
  451. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  452. b.append('\n');
  453. b.append("author a <b> 1 +0000\n");
  454. b.append("committer a <");
  455. byte[] data = encodeASCII(b.toString());
  456. assertCorrupt("bad email", OBJ_COMMIT, data);
  457. assertSkipListAccepts(OBJ_COMMIT, data);
  458. }
  459. @Test
  460. public void testValidTag() throws CorruptObjectException {
  461. StringBuilder b = new StringBuilder();
  462. b.append("object ");
  463. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  464. b.append('\n');
  465. b.append("type commit\n");
  466. b.append("tag test-tag\n");
  467. b.append("tagger A. U. Thor <author@localhost> 1 +0000\n");
  468. byte[] data = encodeASCII(b.toString());
  469. checker.checkTag(data);
  470. checker.check(OBJ_TAG, data);
  471. }
  472. @Test
  473. public void testInvalidTagNoObject1() {
  474. assertCorrupt("no object header", OBJ_TAG, new byte[0]);
  475. }
  476. @Test
  477. public void testInvalidTagNoObject2() {
  478. StringBuilder b = new StringBuilder();
  479. b.append("object\t");
  480. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  481. b.append('\n');
  482. assertCorrupt("no object header", OBJ_TAG, b);
  483. }
  484. @Test
  485. public void testInvalidTagNoObject3() {
  486. StringBuilder b = new StringBuilder();
  487. b.append("obejct ");
  488. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  489. b.append('\n');
  490. assertCorrupt("no object header", OBJ_TAG, b);
  491. }
  492. @Test
  493. public void testInvalidTagNoObject4() {
  494. StringBuilder b = new StringBuilder();
  495. b.append("object ");
  496. b.append("zz9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  497. b.append('\n');
  498. assertCorrupt("invalid object", OBJ_TAG, b);
  499. }
  500. @Test
  501. public void testInvalidTagNoObject5() {
  502. StringBuilder b = new StringBuilder();
  503. b.append("object ");
  504. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  505. b.append(" \n");
  506. assertCorrupt("invalid object", OBJ_TAG, b);
  507. }
  508. @Test
  509. public void testInvalidTagNoObject6() {
  510. StringBuilder b = new StringBuilder();
  511. b.append("object ");
  512. b.append("be9");
  513. assertCorrupt("invalid object", OBJ_TAG, b);
  514. }
  515. @Test
  516. public void testInvalidTagNoType1() {
  517. StringBuilder b = new StringBuilder();
  518. b.append("object ");
  519. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  520. b.append('\n');
  521. assertCorrupt("no type header", OBJ_TAG, b);
  522. }
  523. @Test
  524. public void testInvalidTagNoType2() {
  525. StringBuilder b = new StringBuilder();
  526. b.append("object ");
  527. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  528. b.append('\n');
  529. b.append("type\tcommit\n");
  530. assertCorrupt("no type header", OBJ_TAG, b);
  531. }
  532. @Test
  533. public void testInvalidTagNoType3() {
  534. StringBuilder b = new StringBuilder();
  535. b.append("object ");
  536. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  537. b.append('\n');
  538. b.append("tpye commit\n");
  539. assertCorrupt("no type header", OBJ_TAG, b);
  540. }
  541. @Test
  542. public void testInvalidTagNoType4() {
  543. StringBuilder b = new StringBuilder();
  544. b.append("object ");
  545. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  546. b.append('\n');
  547. b.append("type commit");
  548. assertCorrupt("no tag header", OBJ_TAG, b);
  549. }
  550. @Test
  551. public void testInvalidTagNoTagHeader1() {
  552. StringBuilder b = new StringBuilder();
  553. b.append("object ");
  554. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  555. b.append('\n');
  556. b.append("type commit\n");
  557. assertCorrupt("no tag header", OBJ_TAG, b);
  558. }
  559. @Test
  560. public void testInvalidTagNoTagHeader2() {
  561. StringBuilder b = new StringBuilder();
  562. b.append("object ");
  563. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  564. b.append('\n');
  565. b.append("type commit\n");
  566. b.append("tag\tfoo\n");
  567. assertCorrupt("no tag header", OBJ_TAG, b);
  568. }
  569. @Test
  570. public void testInvalidTagNoTagHeader3() {
  571. StringBuilder b = new StringBuilder();
  572. b.append("object ");
  573. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  574. b.append('\n');
  575. b.append("type commit\n");
  576. b.append("tga foo\n");
  577. assertCorrupt("no tag header", OBJ_TAG, b);
  578. }
  579. @Test
  580. public void testValidTagHasNoTaggerHeader() throws CorruptObjectException {
  581. StringBuilder b = new StringBuilder();
  582. b.append("object ");
  583. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  584. b.append('\n');
  585. b.append("type commit\n");
  586. b.append("tag foo\n");
  587. checker.checkTag(encodeASCII(b.toString()));
  588. }
  589. @Test
  590. public void testInvalidTagInvalidTaggerHeader1()
  591. throws CorruptObjectException {
  592. StringBuilder b = new StringBuilder();
  593. b.append("object ");
  594. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  595. b.append('\n');
  596. b.append("type commit\n");
  597. b.append("tag foo\n");
  598. b.append("tagger \n");
  599. byte[] data = encodeASCII(b.toString());
  600. assertCorrupt("missing email", OBJ_TAG, data);
  601. checker.setAllowInvalidPersonIdent(true);
  602. checker.checkTag(data);
  603. checker.setAllowInvalidPersonIdent(false);
  604. assertSkipListAccepts(OBJ_TAG, data);
  605. }
  606. @Test
  607. public void testInvalidTagInvalidTaggerHeader3()
  608. throws CorruptObjectException {
  609. StringBuilder b = new StringBuilder();
  610. b.append("object ");
  611. b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
  612. b.append('\n');
  613. b.append("type commit\n");
  614. b.append("tag foo\n");
  615. b.append("tagger a < 1 +000\n");
  616. byte[] data = encodeASCII(b.toString());
  617. assertCorrupt("bad email", OBJ_TAG, data);
  618. assertSkipListAccepts(OBJ_TAG, data);
  619. }
  620. @Test
  621. public void testValidEmptyTree() throws CorruptObjectException {
  622. checker.checkTree(new byte[0]);
  623. checker.check(OBJ_TREE, new byte[0]);
  624. }
  625. @Test
  626. public void testValidTree1() throws CorruptObjectException {
  627. StringBuilder b = new StringBuilder();
  628. entry(b, "100644 regular-file");
  629. checker.checkTree(encodeASCII(b.toString()));
  630. }
  631. @Test
  632. public void testValidTree2() throws CorruptObjectException {
  633. StringBuilder b = new StringBuilder();
  634. entry(b, "100755 executable");
  635. checker.checkTree(encodeASCII(b.toString()));
  636. }
  637. @Test
  638. public void testValidTree3() throws CorruptObjectException {
  639. StringBuilder b = new StringBuilder();
  640. entry(b, "40000 tree");
  641. checker.checkTree(encodeASCII(b.toString()));
  642. }
  643. @Test
  644. public void testValidTree4() throws CorruptObjectException {
  645. StringBuilder b = new StringBuilder();
  646. entry(b, "120000 symlink");
  647. checker.checkTree(encodeASCII(b.toString()));
  648. }
  649. @Test
  650. public void testValidTree5() throws CorruptObjectException {
  651. StringBuilder b = new StringBuilder();
  652. entry(b, "160000 git link");
  653. checker.checkTree(encodeASCII(b.toString()));
  654. }
  655. @Test
  656. public void testValidTree6() throws CorruptObjectException {
  657. StringBuilder b = new StringBuilder();
  658. entry(b, "100644 .a");
  659. checker.checkTree(encodeASCII(b.toString()));
  660. }
  661. @Test
  662. public void testValidTreeWithGitmodules() throws CorruptObjectException {
  663. ObjectId treeId = ObjectId
  664. .fromString("0123012301230123012301230123012301230123");
  665. StringBuilder b = new StringBuilder();
  666. ObjectId blobId = entry(b, "100644 .gitmodules");
  667. byte[] data = encodeASCII(b.toString());
  668. checker.checkTree(treeId, data);
  669. assertEquals(1, checker.getGitsubmodules().size());
  670. assertEquals(treeId, checker.getGitsubmodules().get(0).getTreeId());
  671. assertEquals(blobId, checker.getGitsubmodules().get(0).getBlobId());
  672. }
  673. /*
  674. * Windows case insensitivity and long file name handling
  675. * means that .gitmodules has many synonyms.
  676. *
  677. * Examples inspired by git.git's t/t0060-path-utils.sh, by
  678. * Johannes Schindelin and Congyi Wu.
  679. */
  680. @Test
  681. public void testNTFSGitmodules() throws CorruptObjectException {
  682. for (String gitmodules : new String[] {
  683. ".GITMODULES",
  684. ".gitmodules",
  685. ".Gitmodules",
  686. ".gitmoduleS",
  687. "gitmod~1",
  688. "GITMOD~1",
  689. "gitmod~4",
  690. "GI7EBA~1",
  691. "gi7eba~9",
  692. "GI7EB~10",
  693. "GI7E~123",
  694. "~1000000",
  695. "~9999999"
  696. }) {
  697. checker = new ObjectChecker(); // Reset the ObjectChecker state.
  698. checker.setSafeForWindows(true);
  699. ObjectId treeId = ObjectId
  700. .fromString("0123012301230123012301230123012301230123");
  701. StringBuilder b = new StringBuilder();
  702. ObjectId blobId = entry(b, "100644 " + gitmodules);
  703. byte[] data = encodeASCII(b.toString());
  704. checker.checkTree(treeId, data);
  705. assertEquals(1, checker.getGitsubmodules().size());
  706. assertEquals(treeId, checker.getGitsubmodules().get(0).getTreeId());
  707. assertEquals(blobId, checker.getGitsubmodules().get(0).getBlobId());
  708. }
  709. }
  710. @Test
  711. public void testNotGitmodules() throws CorruptObjectException {
  712. for (String notGitmodules : new String[] {
  713. ".gitmodu",
  714. ".gitmodules oh never mind",
  715. }) {
  716. checker = new ObjectChecker(); // Reset the ObjectChecker state.
  717. checker.setSafeForWindows(true);
  718. ObjectId treeId = ObjectId
  719. .fromString("0123012301230123012301230123012301230123");
  720. StringBuilder b = new StringBuilder();
  721. entry(b, "100644 " + notGitmodules);
  722. byte[] data = encodeASCII(b.toString());
  723. checker.checkTree(treeId, data);
  724. assertEquals(0, checker.getGitsubmodules().size());
  725. }
  726. }
  727. /*
  728. * TODO HFS: match ".gitmodules" case-insensitively, after stripping out
  729. * certain zero-length Unicode code points that HFS+ strips out
  730. */
  731. @Test
  732. public void testValidTreeWithGitmodulesUppercase()
  733. throws CorruptObjectException {
  734. ObjectId treeId = ObjectId
  735. .fromString("0123012301230123012301230123012301230123");
  736. StringBuilder b = new StringBuilder();
  737. ObjectId blobId = entry(b, "100644 .GITMODULES");
  738. byte[] data = encodeASCII(b.toString());
  739. checker.setSafeForWindows(true);
  740. checker.checkTree(treeId, data);
  741. assertEquals(1, checker.getGitsubmodules().size());
  742. assertEquals(treeId, checker.getGitsubmodules().get(0).getTreeId());
  743. assertEquals(blobId, checker.getGitsubmodules().get(0).getBlobId());
  744. }
  745. @Test
  746. public void testTreeWithInvalidGitmodules() throws CorruptObjectException {
  747. ObjectId treeId = ObjectId
  748. .fromString("0123012301230123012301230123012301230123");
  749. StringBuilder b = new StringBuilder();
  750. entry(b, "100644 .gitmodulez");
  751. byte[] data = encodeASCII(b.toString());
  752. checker.checkTree(treeId, data);
  753. checker.setSafeForWindows(true);
  754. assertEquals(0, checker.getGitsubmodules().size());
  755. }
  756. @Test
  757. public void testNullSha1InTreeEntry() throws CorruptObjectException {
  758. byte[] data = concat(
  759. encodeASCII("100644 A"), new byte[] { '\0' },
  760. new byte[OBJECT_ID_LENGTH]);
  761. assertCorrupt("entry points to null SHA-1", OBJ_TREE, data);
  762. assertSkipListAccepts(OBJ_TREE, data);
  763. checker.setIgnore(NULL_SHA1, true);
  764. checker.checkTree(data);
  765. }
  766. @Test
  767. public void testValidPosixTree() throws CorruptObjectException {
  768. checkOneName("a<b>c:d|e");
  769. checkOneName("test ");
  770. checkOneName("test.");
  771. checkOneName("NUL");
  772. }
  773. @Test
  774. public void testValidTreeSorting1() throws CorruptObjectException {
  775. StringBuilder b = new StringBuilder();
  776. entry(b, "100644 fooaaa");
  777. entry(b, "100755 foobar");
  778. checker.checkTree(encodeASCII(b.toString()));
  779. }
  780. @Test
  781. public void testValidTreeSorting2() throws CorruptObjectException {
  782. StringBuilder b = new StringBuilder();
  783. entry(b, "100755 fooaaa");
  784. entry(b, "100644 foobar");
  785. checker.checkTree(encodeASCII(b.toString()));
  786. }
  787. @Test
  788. public void testValidTreeSorting3() throws CorruptObjectException {
  789. StringBuilder b = new StringBuilder();
  790. entry(b, "40000 a");
  791. entry(b, "100644 b");
  792. checker.checkTree(encodeASCII(b.toString()));
  793. }
  794. @Test
  795. public void testValidTreeSorting4() throws CorruptObjectException {
  796. StringBuilder b = new StringBuilder();
  797. entry(b, "100644 a");
  798. entry(b, "40000 b");
  799. checker.checkTree(encodeASCII(b.toString()));
  800. }
  801. @Test
  802. public void testValidTreeSorting5() throws CorruptObjectException {
  803. StringBuilder b = new StringBuilder();
  804. entry(b, "100644 a.c");
  805. entry(b, "40000 a");
  806. entry(b, "100644 a0c");
  807. checker.checkTree(encodeASCII(b.toString()));
  808. }
  809. @Test
  810. public void testValidTreeSorting6() throws CorruptObjectException {
  811. StringBuilder b = new StringBuilder();
  812. entry(b, "40000 a");
  813. entry(b, "100644 apple");
  814. checker.checkTree(encodeASCII(b.toString()));
  815. }
  816. @Test
  817. public void testValidTreeSorting7() throws CorruptObjectException {
  818. StringBuilder b = new StringBuilder();
  819. entry(b, "40000 an orang");
  820. entry(b, "40000 an orange");
  821. checker.checkTree(encodeASCII(b.toString()));
  822. }
  823. @Test
  824. public void testValidTreeSorting8() throws CorruptObjectException {
  825. StringBuilder b = new StringBuilder();
  826. entry(b, "100644 a");
  827. entry(b, "100644 a0c");
  828. entry(b, "100644 b");
  829. checker.checkTree(encodeASCII(b.toString()));
  830. }
  831. @Test
  832. public void testAcceptTreeModeWithZero() throws CorruptObjectException {
  833. StringBuilder b = new StringBuilder();
  834. entry(b, "040000 a");
  835. byte[] data = encodeASCII(b.toString());
  836. checker.setAllowLeadingZeroFileMode(true);
  837. checker.checkTree(data);
  838. checker.setAllowLeadingZeroFileMode(false);
  839. assertSkipListAccepts(OBJ_TREE, data);
  840. checker.setIgnore(ZERO_PADDED_FILEMODE, true);
  841. checker.checkTree(data);
  842. }
  843. @Test
  844. public void testInvalidTreeModeStartsWithZero1() {
  845. StringBuilder b = new StringBuilder();
  846. entry(b, "0 a");
  847. assertCorrupt("mode starts with '0'", OBJ_TREE, b);
  848. }
  849. @Test
  850. public void testInvalidTreeModeStartsWithZero2() {
  851. StringBuilder b = new StringBuilder();
  852. entry(b, "0100644 a");
  853. assertCorrupt("mode starts with '0'", OBJ_TREE, b);
  854. }
  855. @Test
  856. public void testInvalidTreeModeStartsWithZero3() {
  857. StringBuilder b = new StringBuilder();
  858. entry(b, "040000 a");
  859. assertCorrupt("mode starts with '0'", OBJ_TREE, b);
  860. }
  861. @Test
  862. public void testInvalidTreeModeNotOctal1() {
  863. StringBuilder b = new StringBuilder();
  864. entry(b, "8 a");
  865. assertCorrupt("invalid mode character", OBJ_TREE, b);
  866. }
  867. @Test
  868. public void testInvalidTreeModeNotOctal2() {
  869. StringBuilder b = new StringBuilder();
  870. entry(b, "Z a");
  871. byte[] data = encodeASCII(b.toString());
  872. assertCorrupt("invalid mode character", OBJ_TREE, data);
  873. assertSkipListRejects("invalid mode character", OBJ_TREE, data);
  874. }
  875. @Test
  876. public void testInvalidTreeModeNotSupportedMode1() {
  877. StringBuilder b = new StringBuilder();
  878. entry(b, "1 a");
  879. byte[] data = encodeASCII(b.toString());
  880. assertCorrupt("invalid mode 1", OBJ_TREE, data);
  881. assertSkipListRejects("invalid mode 1", OBJ_TREE, data);
  882. }
  883. @Test
  884. public void testInvalidTreeModeNotSupportedMode2() {
  885. StringBuilder b = new StringBuilder();
  886. entry(b, "170000 a");
  887. assertCorrupt("invalid mode " + 0170000, OBJ_TREE, b);
  888. }
  889. @Test
  890. public void testInvalidTreeModeMissingName() {
  891. StringBuilder b = new StringBuilder();
  892. b.append("100644");
  893. assertCorrupt("truncated in mode", OBJ_TREE, b);
  894. }
  895. @Test
  896. public void testInvalidTreeNameContainsSlash()
  897. throws CorruptObjectException {
  898. StringBuilder b = new StringBuilder();
  899. entry(b, "100644 a/b");
  900. byte[] data = encodeASCII(b.toString());
  901. assertCorrupt("name contains '/'", OBJ_TREE, data);
  902. assertSkipListAccepts(OBJ_TREE, data);
  903. checker.setIgnore(FULL_PATHNAME, true);
  904. checker.checkTree(data);
  905. }
  906. @Test
  907. public void testInvalidTreeNameIsEmpty() throws CorruptObjectException {
  908. StringBuilder b = new StringBuilder();
  909. entry(b, "100644 ");
  910. byte[] data = encodeASCII(b.toString());
  911. assertCorrupt("zero length name", OBJ_TREE, data);
  912. assertSkipListAccepts(OBJ_TREE, data);
  913. checker.setIgnore(EMPTY_NAME, true);
  914. checker.checkTree(data);
  915. }
  916. @Test
  917. public void testInvalidTreeNameIsDot() throws CorruptObjectException {
  918. StringBuilder b = new StringBuilder();
  919. entry(b, "100644 .");
  920. byte[] data = encodeASCII(b.toString());
  921. assertCorrupt("invalid name '.'", OBJ_TREE, data);
  922. assertSkipListAccepts(OBJ_TREE, data);
  923. checker.setIgnore(HAS_DOT, true);
  924. checker.checkTree(data);
  925. }
  926. @Test
  927. public void testInvalidTreeNameIsDotDot() throws CorruptObjectException {
  928. StringBuilder b = new StringBuilder();
  929. entry(b, "100644 ..");
  930. byte[] data = encodeASCII(b.toString());
  931. assertCorrupt("invalid name '..'", OBJ_TREE, data);
  932. assertSkipListAccepts(OBJ_TREE, data);
  933. checker.setIgnore(HAS_DOTDOT, true);
  934. checker.checkTree(data);
  935. }
  936. @Test
  937. public void testInvalidTreeNameIsGit() throws CorruptObjectException {
  938. StringBuilder b = new StringBuilder();
  939. entry(b, "100644 .git");
  940. byte[] data = encodeASCII(b.toString());
  941. assertCorrupt("invalid name '.git'", OBJ_TREE, data);
  942. assertSkipListAccepts(OBJ_TREE, data);
  943. checker.setIgnore(HAS_DOTGIT, true);
  944. checker.checkTree(data);
  945. }
  946. @Test
  947. public void testInvalidTreeNameIsMixedCaseGit()
  948. throws CorruptObjectException {
  949. StringBuilder b = new StringBuilder();
  950. entry(b, "100644 .GiT");
  951. byte[] data = encodeASCII(b.toString());
  952. assertCorrupt("invalid name '.GiT'", OBJ_TREE, data);
  953. assertSkipListAccepts(OBJ_TREE, data);
  954. checker.setIgnore(HAS_DOTGIT, true);
  955. checker.checkTree(data);
  956. }
  957. @Test
  958. public void testInvalidTreeNameIsMacHFSGit() throws CorruptObjectException {
  959. StringBuilder b = new StringBuilder();
  960. entry(b, "100644 .gi\u200Ct");
  961. byte[] data = encode(b.toString());
  962. // Fine on POSIX.
  963. checker.checkTree(data);
  964. // Rejected on Mac OS.
  965. checker.setSafeForMacOS(true);
  966. assertCorrupt(
  967. "invalid name '.gi\u200Ct' contains ignorable Unicode characters",
  968. OBJ_TREE, data);
  969. assertSkipListAccepts(OBJ_TREE, data);
  970. checker.setIgnore(HAS_DOTGIT, true);
  971. checker.checkTree(data);
  972. }
  973. @Test
  974. public void testInvalidTreeNameIsMacHFSGit2()
  975. throws CorruptObjectException {
  976. StringBuilder b = new StringBuilder();
  977. entry(b, "100644 \u206B.git");
  978. byte[] data = encode(b.toString());
  979. // Fine on POSIX.
  980. checker.checkTree(data);
  981. // Rejected on Mac OS.
  982. checker.setSafeForMacOS(true);
  983. assertCorrupt(
  984. "invalid name '\u206B.git' contains ignorable Unicode characters",
  985. OBJ_TREE, data);
  986. assertSkipListAccepts(OBJ_TREE, data);
  987. checker.setIgnore(HAS_DOTGIT, true);
  988. checker.checkTree(data);
  989. }
  990. @Test
  991. public void testInvalidTreeNameIsMacHFSGit3()
  992. throws CorruptObjectException {
  993. StringBuilder b = new StringBuilder();
  994. entry(b, "100644 .git\uFEFF");
  995. byte[] data = encode(b.toString());
  996. // Fine on POSIX.
  997. checker.checkTree(data);
  998. // Rejected on Mac OS.
  999. checker.setSafeForMacOS(true);
  1000. assertCorrupt(
  1001. "invalid name '.git\uFEFF' contains ignorable Unicode characters",
  1002. OBJ_TREE, data);
  1003. assertSkipListAccepts(OBJ_TREE, data);
  1004. checker.setIgnore(HAS_DOTGIT, true);
  1005. checker.checkTree(data);
  1006. }
  1007. private static byte[] concat(byte[]... b) {
  1008. int n = 0;
  1009. for (byte[] a : b) {
  1010. n += a.length;
  1011. }
  1012. byte[] data = new byte[n];
  1013. n = 0;
  1014. for (byte[] a : b) {
  1015. System.arraycopy(a, 0, data, n, a.length);
  1016. n += a.length;
  1017. }
  1018. return data;
  1019. }
  1020. @Test
  1021. public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd()
  1022. throws CorruptObjectException {
  1023. byte[] data = concat(encode("100644 .git"),
  1024. new byte[] { (byte) 0xef });
  1025. StringBuilder b = new StringBuilder();
  1026. entry(b, "");
  1027. data = concat(data, encode(b.toString()));
  1028. // Fine on POSIX.
  1029. checker.checkTree(data);
  1030. // Rejected on Mac OS.
  1031. checker.setSafeForMacOS(true);
  1032. assertCorrupt(
  1033. "invalid name contains byte sequence '0xef' which is not a valid UTF-8 character",
  1034. OBJ_TREE, data);
  1035. assertSkipListAccepts(OBJ_TREE, data);
  1036. }
  1037. @Test
  1038. public void testInvalidTreeNameIsMacHFSGitCorruptUTF8AtEnd2()
  1039. throws CorruptObjectException {
  1040. byte[] data = concat(encode("100644 .git"),
  1041. new byte[] {
  1042. (byte) 0xe2, (byte) 0xab });
  1043. StringBuilder b = new StringBuilder();
  1044. entry(b, "");
  1045. data = concat(data, encode(b.toString()));
  1046. // Fine on POSIX.
  1047. checker.checkTree(data);
  1048. // Rejected on Mac OS.
  1049. checker.setSafeForMacOS(true);
  1050. assertCorrupt(
  1051. "invalid name contains byte sequence '0xe2ab' which is not a valid UTF-8 character",
  1052. OBJ_TREE, data);
  1053. assertSkipListAccepts(OBJ_TREE, data);
  1054. }
  1055. @Test
  1056. public void testInvalidTreeNameIsNotMacHFSGit()
  1057. throws CorruptObjectException {
  1058. StringBuilder b = new StringBuilder();
  1059. entry(b, "100644 .git\u200Cx");
  1060. byte[] data = encode(b.toString());
  1061. checker.setSafeForMacOS(true);
  1062. checker.checkTree(data);
  1063. }
  1064. @Test
  1065. public void testInvalidTreeNameIsNotMacHFSGit2()
  1066. throws CorruptObjectException {
  1067. StringBuilder b = new StringBuilder();
  1068. entry(b, "100644 .kit\u200C");
  1069. byte[] data = encode(b.toString());
  1070. checker.setSafeForMacOS(true);
  1071. checker.checkTree(data);
  1072. }
  1073. @Test
  1074. public void testInvalidTreeNameIsNotMacHFSGitOtherPlatform()
  1075. throws CorruptObjectException {
  1076. StringBuilder b = new StringBuilder();
  1077. entry(b, "100644 .git\u200C");
  1078. byte[] data = encode(b.toString());
  1079. checker.checkTree(data);
  1080. }
  1081. @Test
  1082. public void testInvalidTreeNameIsDotGitDot() throws CorruptObjectException {
  1083. StringBuilder b = new StringBuilder();
  1084. entry(b, "100644 .git.");
  1085. byte[] data = encodeASCII(b.toString());
  1086. assertCorrupt("invalid name '.git.'", OBJ_TREE, data);
  1087. assertSkipListAccepts(OBJ_TREE, data);
  1088. checker.setIgnore(HAS_DOTGIT, true);
  1089. checker.checkTree(data);
  1090. }
  1091. @Test
  1092. public void testValidTreeNameIsDotGitDotDot()
  1093. throws CorruptObjectException {
  1094. StringBuilder b = new StringBuilder();
  1095. entry(b, "100644 .git..");
  1096. checker.checkTree(encodeASCII(b.toString()));
  1097. }
  1098. @Test
  1099. public void testInvalidTreeNameIsDotGitSpace()
  1100. throws CorruptObjectException {
  1101. StringBuilder b = new StringBuilder();
  1102. entry(b, "100644 .git ");
  1103. byte[] data = encodeASCII(b.toString());
  1104. assertCorrupt("invalid name '.git '", OBJ_TREE, data);
  1105. assertSkipListAccepts(OBJ_TREE, data);
  1106. checker.setIgnore(HAS_DOTGIT, true);
  1107. checker.checkTree(data);
  1108. }
  1109. @Test
  1110. public void testInvalidTreeNameIsDotGitSomething()
  1111. throws CorruptObjectException {
  1112. StringBuilder b = new StringBuilder();
  1113. entry(b, "100644 .gitfoobar");
  1114. byte[] data = encodeASCII(b.toString());
  1115. checker.checkTree(data);
  1116. }
  1117. @Test
  1118. public void testInvalidTreeNameIsDotGitSomethingSpaceSomething()
  1119. throws CorruptObjectException {
  1120. StringBuilder b = new StringBuilder();
  1121. entry(b, "100644 .gitfoo bar");
  1122. byte[] data = encodeASCII(b.toString());
  1123. checker.checkTree(data);
  1124. }
  1125. @Test
  1126. public void testInvalidTreeNameIsDotGitSomethingDot()
  1127. throws CorruptObjectException {
  1128. StringBuilder b = new StringBuilder();
  1129. entry(b, "100644 .gitfoobar.");
  1130. byte[] data = encodeASCII(b.toString());
  1131. checker.checkTree(data);
  1132. }
  1133. @Test
  1134. public void testInvalidTreeNameIsDotGitSomethingDotDot()
  1135. throws CorruptObjectException {
  1136. StringBuilder b = new StringBuilder();
  1137. entry(b, "100644 .gitfoobar..");
  1138. byte[] data = encodeASCII(b.toString());
  1139. checker.checkTree(data);
  1140. }
  1141. @Test
  1142. public void testInvalidTreeNameIsDotGitDotSpace()
  1143. throws CorruptObjectException {
  1144. StringBuilder b = new StringBuilder();
  1145. entry(b, "100644 .git. ");
  1146. byte[] data = encodeASCII(b.toString());
  1147. assertCorrupt("invalid name '.git. '", OBJ_TREE, data);
  1148. assertSkipListAccepts(OBJ_TREE, data);
  1149. checker.setIgnore(HAS_DOTGIT, true);
  1150. checker.checkTree(data);
  1151. }
  1152. @Test
  1153. public void testInvalidTreeNameIsDotGitSpaceDot()
  1154. throws CorruptObjectException {
  1155. StringBuilder b = new StringBuilder();
  1156. entry(b, "100644 .git . ");
  1157. byte[] data = encodeASCII(b.toString());
  1158. assertCorrupt("invalid name '.git . '", OBJ_TREE, data);
  1159. assertSkipListAccepts(OBJ_TREE, data);
  1160. checker.setIgnore(HAS_DOTGIT, true);
  1161. checker.checkTree(data);
  1162. }
  1163. @Test
  1164. public void testInvalidTreeNameIsGITTilde1() throws CorruptObjectException {
  1165. StringBuilder b = new StringBuilder();
  1166. entry(b, "100644 GIT~1");
  1167. byte[] data = encodeASCII(b.toString());
  1168. assertCorrupt("invalid name 'GIT~1'", OBJ_TREE, data);
  1169. assertSkipListAccepts(OBJ_TREE, data);
  1170. checker.setIgnore(HAS_DOTGIT, true);
  1171. checker.checkTree(data);
  1172. }
  1173. @Test
  1174. public void testInvalidTreeNameIsGiTTilde1() throws CorruptObjectException {
  1175. StringBuilder b = new StringBuilder();
  1176. entry(b, "100644 GiT~1");
  1177. byte[] data = encodeASCII(b.toString());
  1178. assertCorrupt("invalid name 'GiT~1'", OBJ_TREE, data);
  1179. assertSkipListAccepts(OBJ_TREE, data);
  1180. checker.setIgnore(HAS_DOTGIT, true);
  1181. checker.checkTree(data);
  1182. }
  1183. @Test
  1184. public void testValidTreeNameIsGitTilde11() throws CorruptObjectException {
  1185. StringBuilder b = new StringBuilder();
  1186. entry(b, "100644 GIT~11");
  1187. byte[] data = encodeASCII(b.toString());
  1188. checker.checkTree(data);
  1189. }
  1190. @Test
  1191. public void testInvalidTreeTruncatedInName() {
  1192. StringBuilder b = new StringBuilder();
  1193. b.append("100644 b");
  1194. byte[] data = encodeASCII(b.toString());
  1195. assertCorrupt("truncated in name", OBJ_TREE, data);
  1196. assertSkipListRejects("truncated in name", OBJ_TREE, data);
  1197. }
  1198. @Test
  1199. public void testInvalidTreeTruncatedInObjectId() {
  1200. StringBuilder b = new StringBuilder();
  1201. b.append("100644 b\0\1\2");
  1202. byte[] data = encodeASCII(b.toString());
  1203. assertCorrupt("truncated in object id", OBJ_TREE, data);
  1204. assertSkipListRejects("truncated in object id", OBJ_TREE, data);
  1205. }
  1206. @Test
  1207. public void testInvalidTreeBadSorting1() throws CorruptObjectException {
  1208. StringBuilder b = new StringBuilder();
  1209. entry(b, "100644 foobar");
  1210. entry(b, "100644 fooaaa");
  1211. byte[] data = encodeASCII(b.toString());
  1212. assertCorrupt("incorrectly sorted", OBJ_TREE, data);
  1213. ObjectId id = idFor(OBJ_TREE, data);
  1214. try {
  1215. checker.check(id, OBJ_TREE, data);
  1216. fail("Did not throw CorruptObjectException");
  1217. } catch (CorruptObjectException e) {
  1218. assertSame(TREE_NOT_SORTED, e.getErrorType());
  1219. assertEquals("treeNotSorted: object " + id.name()
  1220. + ": incorrectly sorted", e.getMessage());
  1221. }
  1222. assertSkipListAccepts(OBJ_TREE, data);
  1223. checker.setIgnore(TREE_NOT_SORTED, true);
  1224. checker.checkTree(data);
  1225. }
  1226. @Test
  1227. public void testInvalidTreeBadSorting2() throws CorruptObjectException {
  1228. StringBuilder b = new StringBuilder();
  1229. entry(b, "40000 a");
  1230. entry(b, "100644 a.c");
  1231. byte[] data = encodeASCII(b.toString());
  1232. assertCorrupt("incorrectly sorted", OBJ_TREE, data);
  1233. assertSkipListAccepts(OBJ_TREE, data);
  1234. checker.setIgnore(TREE_NOT_SORTED, true);
  1235. checker.checkTree(data);
  1236. }
  1237. @Test
  1238. public void testInvalidTreeBadSorting3() throws CorruptObjectException {
  1239. StringBuilder b = new StringBuilder();
  1240. entry(b, "100644 a0c");
  1241. entry(b, "40000 a");
  1242. byte[] data = encodeASCII(b.toString());
  1243. assertCorrupt("incorrectly sorted", OBJ_TREE, data);
  1244. assertSkipListAccepts(OBJ_TREE, data);
  1245. checker.setIgnore(TREE_NOT_SORTED, true);
  1246. checker.checkTree(data);
  1247. }
  1248. @Test
  1249. public void testInvalidTreeDuplicateNames1_File()
  1250. throws CorruptObjectException {
  1251. StringBuilder b = new StringBuilder();
  1252. entry(b, "100644 a");
  1253. entry(b, "100644 a");
  1254. byte[] data = encodeASCII(b.toString());
  1255. assertCorrupt("duplicate entry names", OBJ_TREE, data);
  1256. assertSkipListAccepts(OBJ_TREE, data);
  1257. checker.setIgnore(DUPLICATE_ENTRIES, true);
  1258. checker.checkTree(data);
  1259. }
  1260. @Test
  1261. public void testInvalidTreeDuplicateNames1_Tree()
  1262. throws CorruptObjectException {
  1263. StringBuilder b = new StringBuilder();
  1264. entry(b, "40000 a");
  1265. entry(b, "40000 a");
  1266. byte[] data = encodeASCII(b.toString());
  1267. assertCorrupt("duplicate entry names", OBJ_TREE, data);
  1268. assertSkipListAccepts(OBJ_TREE, data);
  1269. checker.setIgnore(DUPLICATE_ENTRIES, true);
  1270. checker.checkTree(data);
  1271. }
  1272. @Test
  1273. public void testInvalidTreeDuplicateNames2() throws CorruptObjectException {
  1274. StringBuilder b = new StringBuilder();
  1275. entry(b, "100644 a");
  1276. entry(b, "100755 a");
  1277. byte[] data = encodeASCII(b.toString());
  1278. assertCorrupt("duplicate entry names", OBJ_TREE, data);
  1279. assertSkipListAccepts(OBJ_TREE, data);
  1280. checker.setIgnore(DUPLICATE_ENTRIES, true);
  1281. checker.checkTree(data);
  1282. }
  1283. @Test
  1284. public void testInvalidTreeDuplicateNames3() throws CorruptObjectException {
  1285. StringBuilder b = new StringBuilder();
  1286. entry(b, "100644 a");
  1287. entry(b, "40000 a");
  1288. byte[] data = encodeASCII(b.toString());
  1289. assertCorrupt("duplicate entry names", OBJ_TREE, data);
  1290. assertSkipListAccepts(OBJ_TREE, data);
  1291. checker.setIgnore(DUPLICATE_ENTRIES, true);
  1292. checker.checkTree(data);
  1293. }
  1294. @Test
  1295. public void testInvalidTreeDuplicateNames4() throws CorruptObjectException {
  1296. StringBuilder b = new StringBuilder();
  1297. entry(b, "100644 a");
  1298. entry(b, "100644 a.c");
  1299. entry(b, "100644 a.d");
  1300. entry(b, "100644 a.e");
  1301. entry(b, "40000 a");
  1302. entry(b, "100644 zoo");
  1303. byte[] data = encodeASCII(b.toString());
  1304. assertCorrupt("duplicate entry names", OBJ_TREE, data);
  1305. assertSkipListAccepts(OBJ_TREE, data);
  1306. checker.setIgnore(DUPLICATE_ENTRIES, true);
  1307. checker.checkTree(data);
  1308. }
  1309. @Test
  1310. public void testInvalidTreeDuplicateNames5()
  1311. throws UnsupportedEncodingException, CorruptObjectException {
  1312. StringBuilder b = new StringBuilder();
  1313. entry(b, "100644 A");
  1314. entry(b, "100644 a");
  1315. byte[] data = b.toString().getBytes("UTF-8");
  1316. checker.setSafeForWindows(true);
  1317. assertCorrupt("duplicate entry names", OBJ_TREE, data);
  1318. assertSkipListAccepts(OBJ_TREE, data);
  1319. checker.setIgnore(DUPLICATE_ENTRIES, true);
  1320. checker.checkTree(data);
  1321. }
  1322. @Test
  1323. public void testInvalidTreeDuplicateNames6()
  1324. throws UnsupportedEncodingException, CorruptObjectException {
  1325. StringBuilder b = new StringBuilder();
  1326. entry(b, "100644 A");
  1327. entry(b, "100644 a");
  1328. byte[] data = b.toString().getBytes("UTF-8");
  1329. checker.setSafeForMacOS(true);
  1330. assertCorrupt("duplicate entry names", OBJ_TREE, data);
  1331. assertSkipListAccepts(OBJ_TREE, data);
  1332. checker.setIgnore(DUPLICATE_ENTRIES, true);
  1333. checker.checkTree(data);
  1334. }
  1335. @Test
  1336. public void testInvalidTreeDuplicateNames7()
  1337. throws UnsupportedEncodingException, CorruptObjectException {
  1338. StringBuilder b = new StringBuilder();
  1339. entry(b, "100644 \u0065\u0301");
  1340. entry(b, "100644 \u00e9");
  1341. byte[] data = b.toString().getBytes("UTF-8");
  1342. checker.setSafeForMacOS(true);
  1343. assertCorrupt("duplicate entry names", OBJ_TREE, data);
  1344. assertSkipListAccepts(OBJ_TREE, data);
  1345. checker.setIgnore(DUPLICATE_ENTRIES, true);
  1346. checker.checkTree(data);
  1347. }
  1348. @Test
  1349. public void testInvalidTreeDuplicateNames8()
  1350. throws UnsupportedEncodingException, CorruptObjectException {
  1351. StringBuilder b = new StringBuilder();
  1352. entry(b, "100644 A");
  1353. checker.setSafeForMacOS(true);
  1354. checker.checkTree(b.toString().getBytes("UTF-8"));
  1355. }
  1356. @Test
  1357. public void testRejectNulInPathSegment() {
  1358. try {
  1359. checker.checkPathSegment(encodeASCII("a\u0000b"), 0, 3);
  1360. fail("incorrectly accepted NUL in middle of name");
  1361. } catch (CorruptObjectException e) {
  1362. assertEquals("name contains byte 0x00", e.getMessage());
  1363. }
  1364. }
  1365. @Test
  1366. public void testRejectSpaceAtEndOnWindows() {
  1367. checker.setSafeForWindows(true);
  1368. try {
  1369. checkOneName("test ");
  1370. fail("incorrectly accepted space at end");
  1371. } catch (CorruptObjectException e) {
  1372. assertEquals("invalid name ends with ' '", e.getMessage());
  1373. }
  1374. }
  1375. @Test
  1376. public void testBug477090() throws CorruptObjectException {
  1377. checker.setSafeForMacOS(true);
  1378. final byte[] bytes = {
  1379. // U+221E 0xe2889e INFINITY ∞
  1380. (byte) 0xe2, (byte) 0x88, (byte) 0x9e,
  1381. // .html
  1382. 0x2e, 0x68, 0x74, 0x6d, 0x6c };
  1383. checker.checkPathSegment(bytes, 0, bytes.length);
  1384. }
  1385. @Test
  1386. public void testRejectDotAtEndOnWindows() {
  1387. checker.setSafeForWindows(true);
  1388. try {
  1389. checkOneName("test.");
  1390. fail("incorrectly accepted dot at end");
  1391. } catch (CorruptObjectException e) {
  1392. assertEquals("invalid name ends with '.'", e.getMessage());
  1393. }
  1394. }
  1395. @Test
  1396. public void testRejectDevicesOnWindows() {
  1397. checker.setSafeForWindows(true);
  1398. String[] bad = { "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3",
  1399. "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2",
  1400. "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" };
  1401. for (String b : bad) {
  1402. try {
  1403. checkOneName(b);
  1404. fail("incorrectly accepted " + b);
  1405. } catch (CorruptObjectException e) {
  1406. assertEquals("invalid name '" + b + "'", e.getMessage());
  1407. }
  1408. try {
  1409. checkOneName(b + ".txt");
  1410. fail("incorrectly accepted " + b + ".txt");
  1411. } catch (CorruptObjectException e) {
  1412. assertEquals("invalid name '" + b + "'", e.getMessage());
  1413. }
  1414. }
  1415. }
  1416. @Test
  1417. public void testRejectInvalidWindowsCharacters() {
  1418. checker.setSafeForWindows(true);
  1419. rejectName('<');
  1420. rejectName('>');
  1421. rejectName(':');
  1422. rejectName('"');
  1423. rejectName('/');
  1424. rejectName('\\');
  1425. rejectName('|');
  1426. rejectName('?');
  1427. rejectName('*');
  1428. for (int i = 1; i <= 31; i++)
  1429. rejectName((byte) i);
  1430. }
  1431. private void rejectName(char c) {
  1432. try {
  1433. checkOneName("te" + c + "st");
  1434. fail("incorrectly accepted with " + c);
  1435. } catch (CorruptObjectException e) {
  1436. assertEquals("name contains '" + c + "'", e.getMessage());
  1437. }
  1438. }
  1439. private void rejectName(byte c) {
  1440. String h = Integer.toHexString(c);
  1441. try {
  1442. checkOneName("te" + ((char) c) + "st");
  1443. fail("incorrectly accepted with 0x" + h);
  1444. } catch (CorruptObjectException e) {
  1445. assertEquals("name contains byte 0x" + h, e.getMessage());
  1446. }
  1447. }
  1448. private void checkOneName(String name) throws CorruptObjectException {
  1449. StringBuilder b = new StringBuilder();
  1450. entry(b, "100644 " + name);
  1451. checker.checkTree(encodeASCII(b.toString()));
  1452. }
  1453. /*
  1454. * Returns the id generated for the entry
  1455. */
  1456. private static ObjectId entry(StringBuilder b, String modeName) {
  1457. byte[] id = new byte[OBJECT_ID_LENGTH];
  1458. b.append(modeName);
  1459. b.append('\0');
  1460. for (int i = 0; i < OBJECT_ID_LENGTH; i++) {
  1461. b.append((char) i);
  1462. id[i] = (byte) i;
  1463. }
  1464. return ObjectId.fromRaw(id);
  1465. }
  1466. private void assertCorrupt(String msg, int type, StringBuilder b) {
  1467. assertCorrupt(msg, type, encodeASCII(b.toString()));
  1468. }
  1469. private void assertCorrupt(String msg, int type, byte[] data) {
  1470. try {
  1471. checker.check(type, data);
  1472. fail("Did not throw CorruptObjectException");
  1473. } catch (CorruptObjectException e) {
  1474. assertEquals(msg, e.getMessage());
  1475. }
  1476. }
  1477. private void assertSkipListAccepts(int type, byte[] data)
  1478. throws CorruptObjectException {
  1479. ObjectId id = idFor(type, data);
  1480. checker.setSkipList(set(id));
  1481. checker.check(id, type, data);
  1482. checker.setSkipList(null);
  1483. }
  1484. private void assertSkipListRejects(String msg, int type, byte[] data) {
  1485. ObjectId id = idFor(type, data);
  1486. checker.setSkipList(set(id));
  1487. try {
  1488. checker.check(id, type, data);
  1489. fail("Did not throw CorruptObjectException");
  1490. } catch (CorruptObjectException e) {
  1491. assertEquals(msg, e.getMessage());
  1492. }
  1493. checker.setSkipList(null);
  1494. }
  1495. private static ObjectIdSet set(final ObjectId... ids) {
  1496. return new ObjectIdSet() {
  1497. @Override
  1498. public boolean contains(AnyObjectId objectId) {
  1499. for (ObjectId id : ids) {
  1500. if (id.equals(objectId)) {
  1501. return true;
  1502. }
  1503. }
  1504. return false;
  1505. }
  1506. };
  1507. }
  1508. @SuppressWarnings("resource")
  1509. private static ObjectId idFor(int type, byte[] raw) {
  1510. return new ObjectInserter.Formatter().idFor(type, raw);
  1511. }
  1512. }