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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  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 java.io.IOException;
  45. import org.eclipse.jgit.api.Git;
  46. import org.eclipse.jgit.api.errors.GitAPIException;
  47. import org.eclipse.jgit.lib.CLIRepositoryTestCase;
  48. import org.eclipse.jgit.lib.Constants;
  49. import org.eclipse.jgit.revwalk.RevCommit;
  50. import org.junit.Test;
  51. public class StatusTest extends CLIRepositoryTestCase {
  52. @Test
  53. public void testStatusDefault() throws Exception {
  54. executeTest("git status", false, true);
  55. }
  56. @Test
  57. public void testStatusU() throws Exception {
  58. executeTest("git status -u", false, true);
  59. }
  60. @Test
  61. public void testStatusUno() throws Exception {
  62. executeTest("git status -uno", false, false);
  63. }
  64. @Test
  65. public void testStatusUall() throws Exception {
  66. executeTest("git status -uall", false, true);
  67. }
  68. @Test
  69. public void testStatusUntrackedFiles() throws Exception {
  70. executeTest("git status --untracked-files", false, true);
  71. }
  72. @Test
  73. public void testStatusUntrackedFilesNo() throws Exception {
  74. executeTest("git status --untracked-files=no", false, false);
  75. }
  76. @Test
  77. public void testStatusUntrackedFilesAll() throws Exception {
  78. executeTest("git status --untracked-files=all", false, true);
  79. }
  80. @Test
  81. public void testStatusPorcelain() throws Exception {
  82. executeTest("git status --porcelain", true, true);
  83. }
  84. @Test
  85. public void testStatusPorcelainU() throws Exception {
  86. executeTest("git status --porcelain -u", true, true);
  87. }
  88. @Test
  89. public void testStatusPorcelainUno() throws Exception {
  90. executeTest("git status --porcelain -uno", true, false);
  91. }
  92. @Test
  93. public void testStatusPorcelainUall() throws Exception {
  94. executeTest("git status --porcelain -uall", true, true);
  95. }
  96. @Test
  97. public void testStatusPorcelainUntrackedFiles() throws Exception {
  98. executeTest("git status --porcelain --untracked-files", true, true);
  99. }
  100. @Test
  101. public void testStatusPorcelainUntrackedFilesNo() throws Exception {
  102. executeTest("git status --porcelain --untracked-files=no", true, false);
  103. }
  104. @Test
  105. public void testStatusPorcelainUntrackedFilesAll() throws Exception {
  106. executeTest("git status --porcelain --untracked-files=all", true, true);
  107. }
  108. /**
  109. * Executes the test sequence.
  110. *
  111. * @param command
  112. * full git command and parameters to be used
  113. * @param porcelain
  114. * indicates that porcelain format is expected in the output
  115. * @param untrackedFiles
  116. * indicates that untracked files are expected in the output
  117. *
  118. * @throws Exception
  119. * if error during test execution
  120. */
  121. private void executeTest(String command, boolean porcelain,
  122. boolean untrackedFiles) throws Exception {
  123. Git git = new Git(db);
  124. // Write all files
  125. writeAllFiles();
  126. // Test untracked
  127. assertUntrackedFiles(command, porcelain, untrackedFiles);
  128. // Add to index
  129. addFilesToIndex(git);
  130. // Test staged count
  131. assertStagedFiles(command, porcelain, untrackedFiles);
  132. // Commit
  133. makeInitialCommit(git);
  134. assertAfterInitialCommit(command, porcelain, untrackedFiles);
  135. // Make some changes and stage them
  136. makeSomeChangesAndStageThem(git);
  137. // Test staged/not-staged status
  138. assertStagedStatus(command, porcelain, untrackedFiles);
  139. // Create unmerged file
  140. createUnmergedFile(git);
  141. // Commit pending changes
  142. commitPendingChanges(git);
  143. assertUntracked(command, porcelain, untrackedFiles, "master");
  144. // Checkout new branch
  145. checkoutTestBranch(git);
  146. // Test branch status
  147. assertUntracked(command, porcelain, untrackedFiles, "test");
  148. // Commit change and checkout master again
  149. RevCommit testBranch = commitChangesInTestBranch(git);
  150. assertUntracked(command, porcelain, untrackedFiles, "test");
  151. checkoutMasterBranch(git);
  152. // Change the same file and commit
  153. changeUnmergedFileAndCommit(git);
  154. assertUntracked(command, porcelain, untrackedFiles, "master");
  155. // Merge test branch into master
  156. mergeTestBranchInMaster(git, testBranch);
  157. // Test unmerged status
  158. assertUntrackedAndUnmerged(command, porcelain, untrackedFiles, "master");
  159. // Test detached head
  160. detachHead(git);
  161. assertUntrackedAndUnmerged(command, porcelain, untrackedFiles, null);
  162. }
  163. private void writeAllFiles() throws IOException {
  164. writeTrashFile("tracked", "tracked");
  165. writeTrashFile("stagedNew", "stagedNew");
  166. writeTrashFile("stagedModified", "stagedModified");
  167. writeTrashFile("stagedDeleted", "stagedDeleted");
  168. writeTrashFile("trackedModified", "trackedModified");
  169. writeTrashFile("trackedDeleted", "trackedDeleted");
  170. writeTrashFile("untracked", "untracked");
  171. }
  172. private void addFilesToIndex(Git git) throws GitAPIException {
  173. git.add().addFilepattern("tracked").call();
  174. git.add().addFilepattern("stagedModified").call();
  175. git.add().addFilepattern("stagedDeleted").call();
  176. git.add().addFilepattern("trackedModified").call();
  177. git.add().addFilepattern("trackedDeleted").call();
  178. }
  179. private void makeInitialCommit(Git git) throws GitAPIException {
  180. git.commit().setMessage("initial commit").call();
  181. }
  182. private void makeSomeChangesAndStageThem(Git git) throws IOException,
  183. GitAPIException {
  184. writeTrashFile("stagedModified", "stagedModified modified");
  185. deleteTrashFile("stagedDeleted");
  186. writeTrashFile("trackedModified", "trackedModified modified");
  187. deleteTrashFile("trackedDeleted");
  188. git.add().addFilepattern("stagedModified").call();
  189. git.rm().addFilepattern("stagedDeleted").call();
  190. git.add().addFilepattern("stagedNew").call();
  191. }
  192. private void createUnmergedFile(Git git) throws IOException,
  193. GitAPIException {
  194. writeTrashFile("unmerged", "unmerged");
  195. git.add().addFilepattern("unmerged").call();
  196. }
  197. private void commitPendingChanges(Git git) throws GitAPIException {
  198. git.add().addFilepattern("trackedModified").call();
  199. git.rm().addFilepattern("trackedDeleted").call();
  200. git.commit().setMessage("commit before branching").call();
  201. }
  202. private void checkoutTestBranch(Git git) throws GitAPIException {
  203. git.checkout().setCreateBranch(true).setName("test").call();
  204. }
  205. private RevCommit commitChangesInTestBranch(Git git) throws IOException,
  206. GitAPIException {
  207. writeTrashFile("unmerged", "changed in test branch");
  208. git.add().addFilepattern("unmerged").call();
  209. return git.commit()
  210. .setMessage("changed unmerged in test branch").call();
  211. }
  212. private void checkoutMasterBranch(Git git) throws GitAPIException {
  213. git.checkout().setName("master").call();
  214. }
  215. private void changeUnmergedFileAndCommit(Git git) throws IOException,
  216. GitAPIException {
  217. writeTrashFile("unmerged", "changed in master branch");
  218. git.add().addFilepattern("unmerged").call();
  219. git.commit().setMessage("changed unmerged in master branch").call();
  220. }
  221. private void mergeTestBranchInMaster(Git git, RevCommit aCommit)
  222. throws GitAPIException {
  223. git.merge().include(aCommit.getId()).call();
  224. }
  225. private void detachHead(Git git) throws IOException, GitAPIException {
  226. String commitId = db.getRef(Constants.MASTER).getObjectId().name();
  227. git.checkout().setName(commitId).call();
  228. }
  229. private void assertUntrackedFiles(String command, boolean porcelain,
  230. boolean untrackedFiles) throws Exception {
  231. String[] output = new String[0];
  232. if (porcelain) {
  233. if (untrackedFiles) {
  234. output = new String[] { //
  235. "?? stagedDeleted", //
  236. "?? stagedModified", //
  237. "?? stagedNew", //
  238. "?? tracked", //
  239. "?? trackedDeleted", //
  240. "?? trackedModified", //
  241. "?? untracked", //
  242. "" //
  243. };
  244. } else {
  245. output = new String[] { //
  246. "" //
  247. };
  248. }
  249. } else {
  250. if (untrackedFiles) {
  251. output = new String[] { //
  252. "On branch master", //
  253. "Untracked files:", //
  254. "",//
  255. "\tstagedDeleted", //
  256. "\tstagedModified", //
  257. "\tstagedNew", //
  258. "\ttracked", //
  259. "\ttrackedDeleted", //
  260. "\ttrackedModified", //
  261. "\tuntracked", //
  262. "" //
  263. };
  264. } else {
  265. output = new String[] { //
  266. "On branch master", //
  267. "" //
  268. };
  269. }
  270. }
  271. assertArrayOfLinesEquals(output, execute(command));
  272. }
  273. private void assertStagedFiles(String command, boolean porcelain,
  274. boolean untrackedFiles) throws Exception {
  275. String[] output = new String[0];
  276. if (porcelain) {
  277. if (untrackedFiles) {
  278. output = new String[] { //
  279. "A stagedDeleted", //
  280. "A stagedModified", //
  281. "A tracked", //
  282. "A trackedDeleted", //
  283. "A trackedModified", //
  284. "?? stagedNew", //
  285. "?? untracked", //
  286. "" //
  287. };
  288. } else {
  289. output = new String[] { //
  290. "A stagedDeleted", //
  291. "A stagedModified", //
  292. "A tracked", //
  293. "A trackedDeleted", //
  294. "A trackedModified", //
  295. "" //
  296. };
  297. }
  298. } else {
  299. if (untrackedFiles) {
  300. output = new String[] { //
  301. "On branch master", //
  302. "Changes to be committed:", //
  303. "", //
  304. "\tnew file: stagedDeleted", //
  305. "\tnew file: stagedModified", //
  306. "\tnew file: tracked", //
  307. "\tnew file: trackedDeleted", //
  308. "\tnew file: trackedModified", //
  309. "", //
  310. "Untracked files:", //
  311. "", //
  312. "\tstagedNew", //
  313. "\tuntracked", //
  314. "" //
  315. };
  316. } else {
  317. output = new String[] { //
  318. "On branch master", //
  319. "Changes to be committed:", //
  320. "", //
  321. "\tnew file: stagedDeleted", //
  322. "\tnew file: stagedModified", //
  323. "\tnew file: tracked", //
  324. "\tnew file: trackedDeleted", //
  325. "\tnew file: trackedModified", //
  326. "" //
  327. };
  328. }
  329. }
  330. assertArrayOfLinesEquals(output, execute(command));
  331. }
  332. private void assertAfterInitialCommit(String command, boolean porcelain,
  333. boolean untrackedFiles) throws Exception {
  334. String[] output = new String[0];
  335. if (porcelain) {
  336. if (untrackedFiles) {
  337. output = new String[] { //
  338. "?? stagedNew", //
  339. "?? untracked", //
  340. "" //
  341. };
  342. } else {
  343. output = new String[] { //
  344. "" //
  345. };
  346. }
  347. } else {
  348. if (untrackedFiles) {
  349. output = new String[] { //
  350. "On branch master", //
  351. "Untracked files:", //
  352. "", //
  353. "\tstagedNew", //
  354. "\tuntracked", //
  355. "" //
  356. };
  357. } else {
  358. output = new String[] { //
  359. "On branch master", //
  360. "" //
  361. };
  362. }
  363. }
  364. assertArrayOfLinesEquals(output, execute(command));
  365. }
  366. private void assertStagedStatus(String command, boolean porcelain,
  367. boolean untrackedFiles) throws Exception {
  368. String[] output = new String[0];
  369. if (porcelain) {
  370. if (untrackedFiles) {
  371. output = new String[] { //
  372. "D stagedDeleted", //
  373. "M stagedModified", //
  374. "A stagedNew", //
  375. " D trackedDeleted", //
  376. " M trackedModified", //
  377. "?? untracked", //
  378. "" //
  379. };
  380. } else {
  381. output = new String[] { //
  382. "D stagedDeleted", //
  383. "M stagedModified", //
  384. "A stagedNew", //
  385. " D trackedDeleted", //
  386. " M trackedModified", //
  387. "" //
  388. };
  389. }
  390. } else {
  391. if (untrackedFiles) {
  392. output = new String[] { //
  393. "On branch master", //
  394. "Changes to be committed:", //
  395. "", //
  396. "\tdeleted: stagedDeleted", //
  397. "\tmodified: stagedModified", //
  398. "\tnew file: stagedNew", //
  399. "", //
  400. "Changes not staged for commit:", //
  401. "", //
  402. "\tdeleted: trackedDeleted", //
  403. "\tmodified: trackedModified", //
  404. "", //
  405. "Untracked files:", //
  406. "", //
  407. "\tuntracked", //
  408. "" //
  409. };
  410. } else {
  411. output = new String[] { //
  412. "On branch master", //
  413. "Changes to be committed:", //
  414. "", //
  415. "\tdeleted: stagedDeleted", //
  416. "\tmodified: stagedModified", //
  417. "\tnew file: stagedNew", //
  418. "", //
  419. "Changes not staged for commit:", //
  420. "", //
  421. "\tdeleted: trackedDeleted", //
  422. "\tmodified: trackedModified", //
  423. "", //
  424. };
  425. }
  426. }
  427. assertArrayOfLinesEquals(output, execute(command));
  428. }
  429. private void assertUntracked(String command,
  430. boolean porcelain,
  431. boolean untrackedFiles, String branch) throws Exception {
  432. String[] output = new String[0];
  433. String branchHeader = "On branch " + branch;
  434. if (porcelain) {
  435. if (untrackedFiles) {
  436. output = new String[] { //
  437. "?? untracked", //
  438. "" //
  439. };
  440. } else {
  441. output = new String[] { //
  442. "" //
  443. };
  444. }
  445. } else {
  446. if (untrackedFiles) {
  447. output = new String[] { //
  448. branchHeader, //
  449. "Untracked files:", //
  450. "", //
  451. "\tuntracked", //
  452. "" //
  453. };
  454. } else {
  455. output = new String[] { //
  456. branchHeader, //
  457. "" //
  458. };
  459. }
  460. }
  461. assertArrayOfLinesEquals(output, execute(command));
  462. }
  463. private void assertUntrackedAndUnmerged(String command, boolean porcelain,
  464. boolean untrackedFiles, String branch) throws Exception {
  465. String[] output = new String[0];
  466. String branchHeader = (branch == null) //
  467. ? "Not currently on any branch." //
  468. : "On branch " + branch;
  469. if (porcelain) {
  470. if (untrackedFiles) {
  471. output = new String[] { //
  472. "UU unmerged", //
  473. "?? untracked", //
  474. "" //
  475. };
  476. } else {
  477. output = new String[] { //
  478. "UU unmerged", //
  479. "" //
  480. };
  481. }
  482. } else {
  483. if (untrackedFiles) {
  484. output = new String[] { //
  485. branchHeader, //
  486. "Unmerged paths:", //
  487. "", //
  488. "\tboth modified: unmerged", //
  489. "", //
  490. "Untracked files:", //
  491. "", //
  492. "\tuntracked", //
  493. "" //
  494. };
  495. } else {
  496. output = new String[] { //
  497. branchHeader, //
  498. "Unmerged paths:", //
  499. "", //
  500. "\tboth modified: unmerged", //
  501. "" //
  502. };
  503. }
  504. }
  505. assertArrayOfLinesEquals(output, execute(command));
  506. }
  507. }