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.

StatusTest.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. /*
  2. * Copyright (C) 2012, 2015 François Rey <eclipse.org_@_francois_._rey_._name>
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.pgm;
  44. import static org.eclipse.jgit.lib.Constants.MASTER;
  45. import static org.eclipse.jgit.lib.Constants.R_HEADS;
  46. import static org.junit.Assert.assertTrue;
  47. import java.io.IOException;
  48. import org.eclipse.jgit.api.Git;
  49. import org.eclipse.jgit.api.errors.GitAPIException;
  50. import org.eclipse.jgit.lib.CLIRepositoryTestCase;
  51. import org.eclipse.jgit.revwalk.RevCommit;
  52. import org.junit.Test;
  53. public class StatusTest extends CLIRepositoryTestCase {
  54. @Test
  55. public void testPathOptionHelp() throws Exception {
  56. String[] result = execute("git status -h");
  57. assertTrue("Unexpected argument: " + result[1],
  58. result[1].endsWith("[-- path ... ...]"));
  59. }
  60. @Test
  61. public void testStatusDefault() throws Exception {
  62. executeTest("git status", false, true);
  63. }
  64. @Test
  65. public void testStatusU() throws Exception {
  66. executeTest("git status -u", false, true);
  67. }
  68. @Test
  69. public void testStatusUno() throws Exception {
  70. executeTest("git status -uno", false, false);
  71. }
  72. @Test
  73. public void testStatusUall() throws Exception {
  74. executeTest("git status -uall", false, true);
  75. }
  76. @Test
  77. public void testStatusUntrackedFiles() throws Exception {
  78. executeTest("git status --untracked-files", false, true);
  79. }
  80. @Test
  81. public void testStatusUntrackedFilesNo() throws Exception {
  82. executeTest("git status --untracked-files=no", false, false);
  83. }
  84. @Test
  85. public void testStatusUntrackedFilesAll() throws Exception {
  86. executeTest("git status --untracked-files=all", false, true);
  87. }
  88. @Test
  89. public void testStatusPorcelain() throws Exception {
  90. executeTest("git status --porcelain", true, true);
  91. }
  92. @Test
  93. public void testStatusPorcelainU() throws Exception {
  94. executeTest("git status --porcelain -u", true, true);
  95. }
  96. @Test
  97. public void testStatusPorcelainUno() throws Exception {
  98. executeTest("git status --porcelain -uno", true, false);
  99. }
  100. @Test
  101. public void testStatusPorcelainUall() throws Exception {
  102. executeTest("git status --porcelain -uall", true, true);
  103. }
  104. @Test
  105. public void testStatusPorcelainUntrackedFiles() throws Exception {
  106. executeTest("git status --porcelain --untracked-files", true, true);
  107. }
  108. @Test
  109. public void testStatusPorcelainUntrackedFilesNo() throws Exception {
  110. executeTest("git status --porcelain --untracked-files=no", true, false);
  111. }
  112. @Test
  113. public void testStatusPorcelainUntrackedFilesAll() throws Exception {
  114. executeTest("git status --porcelain --untracked-files=all", true, true);
  115. }
  116. /**
  117. * Executes the test sequence.
  118. *
  119. * @param command
  120. * full git command and parameters to be used
  121. * @param porcelain
  122. * indicates that porcelain format is expected in the output
  123. * @param untrackedFiles
  124. * indicates that untracked files are expected in the output
  125. *
  126. * @throws Exception
  127. * if error during test execution
  128. */
  129. private void executeTest(String command, boolean porcelain,
  130. boolean untrackedFiles) throws Exception {
  131. Git git = new Git(db);
  132. // Write all files
  133. writeAllFiles();
  134. // Test untracked
  135. assertUntrackedFiles(command, porcelain, untrackedFiles);
  136. // Add to index
  137. addFilesToIndex(git);
  138. // Test staged count
  139. assertStagedFiles(command, porcelain, untrackedFiles);
  140. // Commit
  141. makeInitialCommit(git);
  142. assertAfterInitialCommit(command, porcelain, untrackedFiles);
  143. // Make some changes and stage them
  144. makeSomeChangesAndStageThem(git);
  145. // Test staged/not-staged status
  146. assertStagedStatus(command, porcelain, untrackedFiles);
  147. // Create unmerged file
  148. createUnmergedFile(git);
  149. // Commit pending changes
  150. commitPendingChanges(git);
  151. assertUntracked(command, porcelain, untrackedFiles, "master");
  152. // Checkout new branch
  153. checkoutTestBranch(git);
  154. // Test branch status
  155. assertUntracked(command, porcelain, untrackedFiles, "test");
  156. // Commit change and checkout master again
  157. RevCommit testBranch = commitChangesInTestBranch(git);
  158. assertUntracked(command, porcelain, untrackedFiles, "test");
  159. checkoutMasterBranch(git);
  160. // Change the same file and commit
  161. changeUnmergedFileAndCommit(git);
  162. assertUntracked(command, porcelain, untrackedFiles, "master");
  163. // Merge test branch into master
  164. mergeTestBranchInMaster(git, testBranch);
  165. // Test unmerged status
  166. assertUntrackedAndUnmerged(command, porcelain, untrackedFiles, "master");
  167. // Test detached head
  168. detachHead(git);
  169. assertUntrackedAndUnmerged(command, porcelain, untrackedFiles, null);
  170. }
  171. private void writeAllFiles() throws IOException {
  172. writeTrashFile("tracked", "tracked");
  173. writeTrashFile("stagedNew", "stagedNew");
  174. writeTrashFile("stagedModified", "stagedModified");
  175. writeTrashFile("stagedDeleted", "stagedDeleted");
  176. writeTrashFile("trackedModified", "trackedModified");
  177. writeTrashFile("trackedDeleted", "trackedDeleted");
  178. writeTrashFile("untracked", "untracked");
  179. }
  180. private void addFilesToIndex(Git git) throws GitAPIException {
  181. git.add().addFilepattern("tracked").call();
  182. git.add().addFilepattern("stagedModified").call();
  183. git.add().addFilepattern("stagedDeleted").call();
  184. git.add().addFilepattern("trackedModified").call();
  185. git.add().addFilepattern("trackedDeleted").call();
  186. }
  187. private void makeInitialCommit(Git git) throws GitAPIException {
  188. git.commit().setMessage("initial commit").call();
  189. }
  190. private void makeSomeChangesAndStageThem(Git git) throws IOException,
  191. GitAPIException {
  192. writeTrashFile("stagedModified", "stagedModified modified");
  193. deleteTrashFile("stagedDeleted");
  194. writeTrashFile("trackedModified", "trackedModified modified");
  195. deleteTrashFile("trackedDeleted");
  196. git.add().addFilepattern("stagedModified").call();
  197. git.rm().addFilepattern("stagedDeleted").call();
  198. git.add().addFilepattern("stagedNew").call();
  199. }
  200. private void createUnmergedFile(Git git) throws IOException,
  201. GitAPIException {
  202. writeTrashFile("unmerged", "unmerged");
  203. git.add().addFilepattern("unmerged").call();
  204. }
  205. private void commitPendingChanges(Git git) throws GitAPIException {
  206. git.add().addFilepattern("trackedModified").call();
  207. git.rm().addFilepattern("trackedDeleted").call();
  208. git.commit().setMessage("commit before branching").call();
  209. }
  210. private void checkoutTestBranch(Git git) throws GitAPIException {
  211. git.checkout().setCreateBranch(true).setName("test").call();
  212. }
  213. private RevCommit commitChangesInTestBranch(Git git) throws IOException,
  214. GitAPIException {
  215. writeTrashFile("unmerged", "changed in test branch");
  216. git.add().addFilepattern("unmerged").call();
  217. return git.commit()
  218. .setMessage("changed unmerged in test branch").call();
  219. }
  220. private void checkoutMasterBranch(Git git) throws GitAPIException {
  221. git.checkout().setName("master").call();
  222. }
  223. private void changeUnmergedFileAndCommit(Git git) throws IOException,
  224. GitAPIException {
  225. writeTrashFile("unmerged", "changed in master branch");
  226. git.add().addFilepattern("unmerged").call();
  227. git.commit().setMessage("changed unmerged in master branch").call();
  228. }
  229. private void mergeTestBranchInMaster(Git git, RevCommit aCommit)
  230. throws GitAPIException {
  231. git.merge().include(aCommit.getId()).call();
  232. }
  233. private void detachHead(Git git) throws IOException, GitAPIException {
  234. String commitId = db.exactRef(R_HEADS + MASTER).getObjectId().name();
  235. git.checkout().setName(commitId).call();
  236. }
  237. private void assertUntrackedFiles(String command, boolean porcelain,
  238. boolean untrackedFiles) throws Exception {
  239. String[] output = new String[0];
  240. if (porcelain) {
  241. if (untrackedFiles) {
  242. output = new String[] { //
  243. "?? stagedDeleted", //
  244. "?? stagedModified", //
  245. "?? stagedNew", //
  246. "?? tracked", //
  247. "?? trackedDeleted", //
  248. "?? trackedModified", //
  249. "?? untracked", //
  250. "" //
  251. };
  252. } else {
  253. output = new String[] { //
  254. "" //
  255. };
  256. }
  257. } else {
  258. if (untrackedFiles) {
  259. output = new String[] { //
  260. "On branch master", //
  261. "Untracked files:", //
  262. "",//
  263. "\tstagedDeleted", //
  264. "\tstagedModified", //
  265. "\tstagedNew", //
  266. "\ttracked", //
  267. "\ttrackedDeleted", //
  268. "\ttrackedModified", //
  269. "\tuntracked", //
  270. "" //
  271. };
  272. } else {
  273. output = new String[] { //
  274. "On branch master", //
  275. "" //
  276. };
  277. }
  278. }
  279. assertArrayOfLinesEquals(output, execute(command));
  280. }
  281. private void assertStagedFiles(String command, boolean porcelain,
  282. boolean untrackedFiles) throws Exception {
  283. String[] output = new String[0];
  284. if (porcelain) {
  285. if (untrackedFiles) {
  286. output = new String[] { //
  287. "A stagedDeleted", //
  288. "A stagedModified", //
  289. "A tracked", //
  290. "A trackedDeleted", //
  291. "A trackedModified", //
  292. "?? stagedNew", //
  293. "?? untracked", //
  294. "" //
  295. };
  296. } else {
  297. output = new String[] { //
  298. "A stagedDeleted", //
  299. "A stagedModified", //
  300. "A tracked", //
  301. "A trackedDeleted", //
  302. "A trackedModified", //
  303. "" //
  304. };
  305. }
  306. } else {
  307. if (untrackedFiles) {
  308. output = new String[] { //
  309. "On branch master", //
  310. "Changes to be committed:", //
  311. "", //
  312. "\tnew file: stagedDeleted", //
  313. "\tnew file: stagedModified", //
  314. "\tnew file: tracked", //
  315. "\tnew file: trackedDeleted", //
  316. "\tnew file: trackedModified", //
  317. "", //
  318. "Untracked files:", //
  319. "", //
  320. "\tstagedNew", //
  321. "\tuntracked", //
  322. "" //
  323. };
  324. } else {
  325. output = new String[] { //
  326. "On branch master", //
  327. "Changes to be committed:", //
  328. "", //
  329. "\tnew file: stagedDeleted", //
  330. "\tnew file: stagedModified", //
  331. "\tnew file: tracked", //
  332. "\tnew file: trackedDeleted", //
  333. "\tnew file: trackedModified", //
  334. "" //
  335. };
  336. }
  337. }
  338. assertArrayOfLinesEquals(output, execute(command));
  339. }
  340. private void assertAfterInitialCommit(String command, boolean porcelain,
  341. boolean untrackedFiles) throws Exception {
  342. String[] output = new String[0];
  343. if (porcelain) {
  344. if (untrackedFiles) {
  345. output = new String[] { //
  346. "?? stagedNew", //
  347. "?? untracked", //
  348. "" //
  349. };
  350. } else {
  351. output = new String[] { //
  352. "" //
  353. };
  354. }
  355. } else {
  356. if (untrackedFiles) {
  357. output = new String[] { //
  358. "On branch master", //
  359. "Untracked files:", //
  360. "", //
  361. "\tstagedNew", //
  362. "\tuntracked", //
  363. "" //
  364. };
  365. } else {
  366. output = new String[] { //
  367. "On branch master", //
  368. "" //
  369. };
  370. }
  371. }
  372. assertArrayOfLinesEquals(output, execute(command));
  373. }
  374. private void assertStagedStatus(String command, boolean porcelain,
  375. boolean untrackedFiles) throws Exception {
  376. String[] output = new String[0];
  377. if (porcelain) {
  378. if (untrackedFiles) {
  379. output = new String[] { //
  380. "D stagedDeleted", //
  381. "M stagedModified", //
  382. "A stagedNew", //
  383. " D trackedDeleted", //
  384. " M trackedModified", //
  385. "?? untracked", //
  386. "" //
  387. };
  388. } else {
  389. output = new String[] { //
  390. "D stagedDeleted", //
  391. "M stagedModified", //
  392. "A stagedNew", //
  393. " D trackedDeleted", //
  394. " M trackedModified", //
  395. "" //
  396. };
  397. }
  398. } else {
  399. if (untrackedFiles) {
  400. output = new String[] { //
  401. "On branch master", //
  402. "Changes to be committed:", //
  403. "", //
  404. "\tdeleted: stagedDeleted", //
  405. "\tmodified: stagedModified", //
  406. "\tnew file: stagedNew", //
  407. "", //
  408. "Changes not staged for commit:", //
  409. "", //
  410. "\tdeleted: trackedDeleted", //
  411. "\tmodified: trackedModified", //
  412. "", //
  413. "Untracked files:", //
  414. "", //
  415. "\tuntracked", //
  416. "" //
  417. };
  418. } else {
  419. output = new String[] { //
  420. "On branch master", //
  421. "Changes to be committed:", //
  422. "", //
  423. "\tdeleted: stagedDeleted", //
  424. "\tmodified: stagedModified", //
  425. "\tnew file: stagedNew", //
  426. "", //
  427. "Changes not staged for commit:", //
  428. "", //
  429. "\tdeleted: trackedDeleted", //
  430. "\tmodified: trackedModified", //
  431. "", //
  432. };
  433. }
  434. }
  435. assertArrayOfLinesEquals(output, execute(command));
  436. }
  437. private void assertUntracked(String command,
  438. boolean porcelain,
  439. boolean untrackedFiles, String branch) throws Exception {
  440. String[] output = new String[0];
  441. String branchHeader = "On branch " + branch;
  442. if (porcelain) {
  443. if (untrackedFiles) {
  444. output = new String[] { //
  445. "?? untracked", //
  446. "" //
  447. };
  448. } else {
  449. output = new String[] { //
  450. "" //
  451. };
  452. }
  453. } else {
  454. if (untrackedFiles) {
  455. output = new String[] { //
  456. branchHeader, //
  457. "Untracked files:", //
  458. "", //
  459. "\tuntracked", //
  460. "" //
  461. };
  462. } else {
  463. output = new String[] { //
  464. branchHeader, //
  465. "" //
  466. };
  467. }
  468. }
  469. assertArrayOfLinesEquals(output, execute(command));
  470. }
  471. private void assertUntrackedAndUnmerged(String command, boolean porcelain,
  472. boolean untrackedFiles, String branch) throws Exception {
  473. String[] output = new String[0];
  474. String branchHeader = (branch == null) //
  475. ? "Not currently on any branch." //
  476. : "On branch " + branch;
  477. if (porcelain) {
  478. if (untrackedFiles) {
  479. output = new String[] { //
  480. "UU unmerged", //
  481. "?? untracked", //
  482. "" //
  483. };
  484. } else {
  485. output = new String[] { //
  486. "UU unmerged", //
  487. "" //
  488. };
  489. }
  490. } else {
  491. if (untrackedFiles) {
  492. output = new String[] { //
  493. branchHeader, //
  494. "Unmerged paths:", //
  495. "", //
  496. "\tboth modified: unmerged", //
  497. "", //
  498. "Untracked files:", //
  499. "", //
  500. "\tuntracked", //
  501. "" //
  502. };
  503. } else {
  504. output = new String[] { //
  505. branchHeader, //
  506. "Unmerged paths:", //
  507. "", //
  508. "\tboth modified: unmerged", //
  509. "" //
  510. };
  511. }
  512. }
  513. assertArrayOfLinesEquals(output, execute(command));
  514. }
  515. }