view test/org/tmatesoft/hg/test/TestManifest.java @ 529:95bdcf75e71e

Command to schedule addition/removal of repository files
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Mon, 21 Jan 2013 19:41:51 +0100
parents 59b7c817bc4d
children
line wrap: on
line source
/*
 * Copyright (c) 2011-2012 TMate Software Ltd
 *  
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * For information on how to redistribute this software under
 * the terms of a license other than GNU General Public License
 * contact TMate Software at support@hg4j.com
 */
package org.tmatesoft.hg.test;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.*;
import static org.tmatesoft.hg.repo.HgRepository.TIP;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.regex.Pattern;

import org.junit.Rule;
import org.junit.Test;
import org.tmatesoft.hg.core.HgManifestHandler;
import org.tmatesoft.hg.core.HgFileRevision;
import org.tmatesoft.hg.core.HgManifestCommand;
import org.tmatesoft.hg.core.Nodeid;
import org.tmatesoft.hg.internal.IntMap;
import org.tmatesoft.hg.repo.HgLookup;
import org.tmatesoft.hg.repo.HgManifest;
import org.tmatesoft.hg.repo.HgRepository;
import org.tmatesoft.hg.repo.HgManifest.Flags;
import org.tmatesoft.hg.util.Path;


/**
 *
 * @author Artem Tikhomirov
 * @author TMate Software Ltd.
 */
public class TestManifest {

	@Rule
	public ErrorCollectorExt errorCollector = new ErrorCollectorExt();

	private final HgRepository repo;
	private ManifestOutputParser manifestParser;
	private ExecHelper eh;
	final LinkedList<HgFileRevision> revisions = new LinkedList<HgFileRevision>();
	private HgManifestHandler handler  = new HgManifestHandler() {
		
		public void file(HgFileRevision fileRevision) {
			revisions.add(fileRevision);
		}
		
		public void end(Nodeid manifestRevision) {}
		public void dir(Path p) {}
		public void begin(Nodeid manifestRevision) {}
	};

	public static void main(String[] args) throws Throwable {
		TestManifest tm = new TestManifest();
		tm.testTip();
		tm.testFirstRevision();
		tm.testRevisionInTheMiddle();
		tm.testWalkFileRevisions();
		tm.errorCollector.verify();
	}
	
	public TestManifest() throws Exception {
		this(new HgLookup().detectFromWorkingDir());
	}

	private TestManifest(HgRepository hgRepo) {
		repo = hgRepo;
		assertTrue(!repo.isInvalid());
		eh = new ExecHelper(manifestParser = new ManifestOutputParser(), repo.getWorkingDir());
	}

	@Test
	public void testTip() throws Exception {
		testRevision(TIP);
	}

	@Test
	public void testFirstRevision() throws Exception {
		testRevision(0);
	}
	
	@Test
	public void testRevisionInTheMiddle() throws Exception {
		int rev = repo.getManifest().getRevisionCount() / 2;
		if (rev == 0) {
			throw new IllegalStateException("Need manifest with few revisions");
		}
		testRevision(rev);
	}
	
	@Test
	public void testWalkFileRevisions() throws Exception {
		//  hg --debug manifest --rev 150 | grep cmdline/org/tmatesoft/hg/console/Main.java
		String fname = "cmdline/org/tmatesoft/hg/console/Main.java";
		Pattern ptrn = Pattern.compile("(\\w+)\\s+\\d{3}\\s+\\Q" + fname + "\\E$", Pattern.MULTILINE);
		OutputParser.Stub output = new OutputParser.Stub();
		ExecHelper eh = new ExecHelper(output, repo.getWorkingDir());
		int[] revisions = new int[] { 100, 150, 200, 210, 300 };
		final IntMap<Nodeid> expected = new IntMap<Nodeid>(10);
		for (int r : revisions) {
			eh.run("hg", "--debug", "manifest", "--rev", Integer.toString(r));
			for (String l : output.lines(ptrn, 1)) {
				assertFalse(expected.containsKey(r));
				expected.put(r, Nodeid.fromAscii(l));
			}
			if (!expected.containsKey(r)) {
				expected.put(r, Nodeid.NULL);
			}
		}
		assertEquals(revisions.length, expected.size());
		final Path path = Path.create(fname);
		repo.getManifest().walkFileRevisions(path, new HgManifest.Inspector() {

			private Nodeid expectedNodeid;
			private int clogRev;

			public boolean begin(int mainfestRevision, Nodeid nid, int changelogRevision) {
				clogRev = changelogRevision;
				assertTrue(expected.containsKey(changelogRevision));
				expectedNodeid = expected.get(changelogRevision);
				// we walk revisions of specific file, hence can't get into manifest without
				// that file, expectedNodeid should have been reported by `hg manifest`:
				assertTrue(!expectedNodeid.isNull());
				return true;
			}

			public boolean next(Nodeid nid, Path fname, Flags flags) {
				assertEquals(path, fname); // only selected path shall pass
				assertEquals(expectedNodeid, nid);
				expected.remove(clogRev);
				return true;
			}
			
			public boolean end(int manifestRevision) {
				return true;
			}
			
		}, revisions);
		for (int r : revisions) {
			if (expected.containsKey(r)) {
				// Each  manifest entry reported by `hg manifest` shall be 
				// reported (and removed) by walkFileRevisions(), too. Only null nodeids
				// (revisions where the file was missing) are left 
				assertTrue(expected.get(r).isNull());
			}
		}
	}


	private void testRevision(int rev) throws Exception {
		manifestParser.reset();
		eh.run("hg", "manifest", "--debug", "--rev", String.valueOf(rev == TIP ? -1 : rev));
		revisions.clear();
		new HgManifestCommand(repo).changeset(rev).execute(handler);
		report("manifest " + (rev == TIP ? "TIP:" : "--rev " + rev));
	}

	private void report(String what) throws Exception {
		final Map<Path, Nodeid> cmdLineResult = new LinkedHashMap<Path, Nodeid>(manifestParser.getResult());
		for (HgFileRevision fr : revisions) {
			Nodeid nid = cmdLineResult.remove(fr.getPath());
			errorCollector.checkThat("Extra " + fr.getPath() + " in Java result", nid, notNullValue());
			if (nid != null) {
				errorCollector.checkThat("Non-matching nodeid:" + nid, nid, equalTo(fr.getRevision()));
			}
		}
		errorCollector.checkThat("Non-matched entries from command line:", cmdLineResult, equalTo(Collections.<Path,Nodeid>emptyMap()));
	}
}