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 48KB

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