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

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