tikhomirov@61: /* tikhomirov@66: * Copyright (c) 2011 TMate Software Ltd tikhomirov@66: * tikhomirov@66: * This program is free software; you can redistribute it and/or modify tikhomirov@66: * it under the terms of the GNU General Public License as published by tikhomirov@66: * the Free Software Foundation; version 2 of the License. tikhomirov@66: * tikhomirov@66: * This program is distributed in the hope that it will be useful, tikhomirov@66: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@66: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@66: * GNU General Public License for more details. tikhomirov@66: * tikhomirov@66: * For information on how to redistribute this software under tikhomirov@66: * the terms of a license other than GNU General Public License tikhomirov@102: * contact TMate Software at support@hg4j.com tikhomirov@61: */ tikhomirov@66: package org.tmatesoft.hg.test; tikhomirov@61: tikhomirov@103: import static org.hamcrest.CoreMatchers.equalTo; tikhomirov@74: import static org.tmatesoft.hg.repo.HgRepository.TIP; tikhomirov@68: tikhomirov@61: import java.util.Collection; tikhomirov@103: import java.util.Collections; tikhomirov@75: import java.util.HashMap; tikhomirov@61: import java.util.LinkedList; tikhomirov@61: import java.util.List; tikhomirov@61: tikhomirov@101: import org.junit.Assume; tikhomirov@103: import org.junit.Rule; tikhomirov@101: import org.junit.Test; tikhomirov@93: import org.tmatesoft.hg.core.Path; tikhomirov@68: import org.tmatesoft.hg.core.StatusCommand; tikhomirov@101: import org.tmatesoft.hg.repo.HgLookup; tikhomirov@74: import org.tmatesoft.hg.repo.HgRepository; tikhomirov@94: import org.tmatesoft.hg.repo.HgStatusCollector; tikhomirov@94: import org.tmatesoft.hg.repo.HgWorkingCopyStatusCollector; tikhomirov@68: tikhomirov@61: tikhomirov@61: /** tikhomirov@76: * tikhomirov@66: * @author Artem Tikhomirov tikhomirov@66: * @author TMate Software Ltd. tikhomirov@61: */ tikhomirov@61: public class TestStatus { tikhomirov@61: tikhomirov@103: @Rule tikhomirov@103: public ErrorCollectorExt errorCollector = new ErrorCollectorExt(); tikhomirov@103: tikhomirov@68: private final HgRepository repo; tikhomirov@66: private StatusOutputParser statusParser; tikhomirov@66: private ExecHelper eh; tikhomirov@66: tikhomirov@103: public static void main(String[] args) throws Throwable { tikhomirov@101: TestStatus test = new TestStatus(); tikhomirov@66: test.testLowLevel(); tikhomirov@99: test.testStatusCommand(); tikhomirov@100: test.testPerformance(); tikhomirov@103: test.errorCollector.verify(); tikhomirov@66: } tikhomirov@66: tikhomirov@101: public TestStatus() throws Exception { tikhomirov@101: this(new HgLookup().detectFromWorkingDir()); tikhomirov@101: } tikhomirov@101: tikhomirov@101: private TestStatus(HgRepository hgRepo) { tikhomirov@66: repo = hgRepo; tikhomirov@101: Assume.assumeTrue(!repo.isInvalid()); tikhomirov@66: statusParser = new StatusOutputParser(); tikhomirov@66: eh = new ExecHelper(statusParser, null); tikhomirov@66: } tikhomirov@66: tikhomirov@101: @Test tikhomirov@66: public void testLowLevel() throws Exception { tikhomirov@94: final HgWorkingCopyStatusCollector wcc = new HgWorkingCopyStatusCollector(repo); tikhomirov@68: statusParser.reset(); tikhomirov@61: eh.run("hg", "status", "-A"); tikhomirov@94: HgStatusCollector.Record r = wcc.status(HgRepository.TIP); tikhomirov@62: report("hg status -A", r, statusParser); tikhomirov@62: // tikhomirov@62: statusParser.reset(); tikhomirov@62: int revision = 3; tikhomirov@62: eh.run("hg", "status", "-A", "--rev", String.valueOf(revision)); tikhomirov@62: r = wcc.status(revision); tikhomirov@62: report("status -A --rev " + revision, r, statusParser); tikhomirov@62: // tikhomirov@62: statusParser.reset(); tikhomirov@62: eh.run("hg", "status", "-A", "--change", String.valueOf(revision)); tikhomirov@94: r = new HgStatusCollector.Record(); tikhomirov@94: new HgStatusCollector(repo).change(revision, r); tikhomirov@62: report("status -A --change " + revision, r, statusParser); tikhomirov@88: // tikhomirov@88: statusParser.reset(); tikhomirov@88: int rev2 = 80; tikhomirov@88: final String range = String.valueOf(revision) + ":" + String.valueOf(rev2); tikhomirov@88: eh.run("hg", "status", "-A", "--rev", range); tikhomirov@94: r = new HgStatusCollector(repo).status(revision, rev2); tikhomirov@88: report("Status -A -rev " + range, r, statusParser); tikhomirov@62: } tikhomirov@62: tikhomirov@101: @Test tikhomirov@66: public void testStatusCommand() throws Exception { tikhomirov@68: final StatusCommand sc = new StatusCommand(repo).all(); tikhomirov@94: HgStatusCollector.Record r; tikhomirov@68: statusParser.reset(); tikhomirov@68: eh.run("hg", "status", "-A"); tikhomirov@94: sc.execute(r = new HgStatusCollector.Record()); tikhomirov@68: report("hg status -A", r, statusParser); tikhomirov@68: // tikhomirov@68: statusParser.reset(); tikhomirov@68: int revision = 3; tikhomirov@68: eh.run("hg", "status", "-A", "--rev", String.valueOf(revision)); tikhomirov@94: sc.base(revision).execute(r = new HgStatusCollector.Record()); tikhomirov@68: report("status -A --rev " + revision, r, statusParser); tikhomirov@68: // tikhomirov@68: statusParser.reset(); tikhomirov@68: eh.run("hg", "status", "-A", "--change", String.valueOf(revision)); tikhomirov@94: sc.base(TIP).revision(revision).execute(r = new HgStatusCollector.Record()); tikhomirov@68: report("status -A --change " + revision, r, statusParser); tikhomirov@68: tikhomirov@68: // TODO check not -A, but defaults()/custom set of modifications tikhomirov@66: } tikhomirov@66: tikhomirov@76: public void testRemovedAgainstNonTip() { tikhomirov@76: /* tikhomirov@76: status --rev N when a file added past revision N was removed ((both physically and in dirstate), but not yet committed tikhomirov@76: tikhomirov@76: Reports extra REMOVED file (the one added and removed in between). Shall not tikhomirov@76: */ tikhomirov@76: } tikhomirov@76: tikhomirov@100: /* tikhomirov@100: * With warm-up of previous tests, 10 runs, time in milliseconds tikhomirov@100: * 'hg status -A': Native client total 953 (95 per run), Java client 94 (9) tikhomirov@100: * 'hg status -A --rev 3:80': Native client total 1828 (182 per run), Java client 235 (23) tikhomirov@100: * 'hg log --debug', 10 runs: Native client total 1766 (176 per run), Java client 78 (7) tikhomirov@100: */ tikhomirov@100: public void testPerformance() throws Exception { tikhomirov@100: final int runs = 10; tikhomirov@100: final long start1 = System.currentTimeMillis(); tikhomirov@100: for (int i = 0; i < runs; i++) { tikhomirov@100: statusParser.reset(); tikhomirov@100: eh.run("hg", "status", "-A", "--rev", "3:80"); tikhomirov@100: } tikhomirov@100: final long start2 = System.currentTimeMillis(); tikhomirov@100: for (int i = 0; i < runs; i++) { tikhomirov@100: HgStatusCollector.Record r = new HgStatusCollector.Record(); tikhomirov@100: new StatusCommand(repo).all().base(3).revision(80).execute(r); tikhomirov@100: } tikhomirov@100: final long end = System.currentTimeMillis(); tikhomirov@100: System.out.printf("'hg status -A --rev 3:80', %d runs: Native client total %d (%d per run), Java client %d (%d)\n", runs, start2-start1, (start2-start1)/runs, end-start2, (end-start2)/runs); tikhomirov@100: } tikhomirov@100: tikhomirov@100: tikhomirov@103: private void report(String what, HgStatusCollector.Record r, StatusOutputParser statusParser) { tikhomirov@103: reportNotEqual(what + "#MODIFIED", r.getModified(), statusParser.getModified()); tikhomirov@103: reportNotEqual(what + "#ADDED", r.getAdded(), statusParser.getAdded()); tikhomirov@103: reportNotEqual(what + "#REMOVED", r.getRemoved(), statusParser.getRemoved()); tikhomirov@103: reportNotEqual(what + "#CLEAN", r.getClean(), statusParser.getClean()); tikhomirov@103: reportNotEqual(what + "#IGNORED", r.getIgnored(), statusParser.getIgnored()); tikhomirov@103: reportNotEqual(what + "#MISSING", r.getMissing(), statusParser.getMissing()); tikhomirov@103: reportNotEqual(what + "#UNKNOWN", r.getUnknown(), statusParser.getUnknown()); tikhomirov@93: List copiedKeyDiff = difference(r.getCopied().keySet(), statusParser.getCopied().keySet()); tikhomirov@93: HashMap copyDiff = new HashMap(); tikhomirov@75: if (copiedKeyDiff.isEmpty()) { tikhomirov@93: for (Path jk : r.getCopied().keySet()) { tikhomirov@93: Path jv = r.getCopied().get(jk); tikhomirov@75: if (statusParser.getCopied().containsKey(jk)) { tikhomirov@93: Path cmdv = statusParser.getCopied().get(jk); tikhomirov@75: if (!jv.equals(cmdv)) { tikhomirov@75: copyDiff.put(jk, jv + " instead of " + cmdv); tikhomirov@75: } tikhomirov@75: } else { tikhomirov@75: copyDiff.put(jk, "ERRONEOUSLY REPORTED IN JAVA"); tikhomirov@75: } tikhomirov@75: } tikhomirov@75: } tikhomirov@103: errorCollector.checkThat(what + "#Non-matching 'copied' keys: ", copiedKeyDiff, equalTo(Collections.emptyList())); tikhomirov@103: errorCollector.checkThat(what + "#COPIED", copyDiff, equalTo(Collections.emptyMap())); tikhomirov@61: } tikhomirov@61: tikhomirov@103: private void reportNotEqual(String what, Collection l1, Collection l2) { tikhomirov@61: List diff = difference(l1, l2); tikhomirov@103: errorCollector.checkThat(what, diff, equalTo(Collections.emptyList())); tikhomirov@61: } tikhomirov@61: tikhomirov@61: private static List difference(Collection l1, Collection l2) { tikhomirov@61: LinkedList result = new LinkedList(l2); tikhomirov@61: for (T t : l1) { tikhomirov@61: if (l2.contains(t)) { tikhomirov@61: result.remove(t); tikhomirov@61: } else { tikhomirov@61: result.add(t); tikhomirov@61: } tikhomirov@61: } tikhomirov@61: return result; tikhomirov@61: } tikhomirov@61: }