changeset 372:155c1893bda4

Issue 22: UnsupportedOperationException on empty manifest entry
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 06 Jan 2012 00:42:15 +0300
parents aa2e589d4e84
children dd492acd2431
files src/org/tmatesoft/hg/repo/HgManifest.java test-data/test-repos.jar test/org/tmatesoft/hg/test/TestStatus.java
diffstat 3 files changed, 70 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/repo/HgManifest.java	Sat Dec 31 01:04:22 2011 +0300
+++ b/src/org/tmatesoft/hg/repo/HgManifest.java	Fri Jan 06 00:42:15 2012 +0300
@@ -324,58 +324,61 @@
 					iterateControl.stop();
 					return;
 				}
-				Path fname = null;
-				Flags flags = null;
-				Nodeid nid = null;
-				int i;
-				byte[] data = da.byteArray();
-				for (i = 0; i < actualLen; i++) {
-					int x = i;
-					for( ; data[i] != '\n' && i < actualLen; i++) {
-						if (fname == null && data[i] == 0) {
-							PathProxy px = fnamePool.unify(new PathProxy(data, x, i - x));
-							// if (cached = fnamePool.unify(px))== px then cacheMiss, else cacheHit
-							// cpython 0..10k: hits: 15 989 152, misses: 3020
-							fname = px.freeze();
-							x = i+1;
+				if (!da.isEmpty()) {
+					// although unlikely, manifest entry may be empty, when all files have been deleted from the repository
+					Path fname = null;
+					Flags flags = null;
+					Nodeid nid = null;
+					int i;
+					byte[] data = da.byteArray();
+					for (i = 0; i < actualLen; i++) {
+						int x = i;
+						for( ; data[i] != '\n' && i < actualLen; i++) {
+							if (fname == null && data[i] == 0) {
+								PathProxy px = fnamePool.unify(new PathProxy(data, x, i - x));
+								// if (cached = fnamePool.unify(px))== px then cacheMiss, else cacheHit
+								// cpython 0..10k: hits: 15 989 152, misses: 3020
+								fname = px.freeze();
+								x = i+1;
+							}
 						}
+						if (i < actualLen) {
+							assert data[i] == '\n'; 
+							int nodeidLen = i - x < 40 ? i-x : 40; // if > 40, there are flags
+							DigestHelper.ascii2bin(data, x, nodeidLen, nodeidLookupBuffer); // ignore return value as it's unlikely to have NULL in manifest
+							nid = new Nodeid(nodeidLookupBuffer, false); // this Nodeid is for pool lookup only, mock object
+							Nodeid cached = nodeidPool.unify(nid);
+							if (cached == nid) {
+								// buffer now belongs to the cached nodeid
+								nodeidLookupBuffer = new byte[20];
+							} else {
+								nid = cached; // use existing version, discard the lookup object
+							} // for cpython 0..10k, cache hits are 15 973 301, vs 18871 misses.
+							thisRevPool.record(nid); // memorize revision for the next iteration. 
+							if (nodeidLen + x < i) {
+								// 'x' and 'l' for executable bits and symlinks?
+								// hg --debug manifest shows 644 for each regular file in my repo
+								// for cpython 0..10k, there are 4361062 flag checks, and there's only 1 unique flag
+								flags = Flags.parse(data, x + nodeidLen, i-x-nodeidLen);
+							} else {
+								flags = null;
+							}
+							boolean good2go;
+							if (inspector2 == null) {
+								String flagString = flags == null ? null : flags.nativeString();
+								good2go = inspector.next(nid, fname.toString(), flagString);
+							} else {
+								good2go = inspector2.next(nid, fname, flags);
+							}
+							if (!good2go) {
+								iterateControl.stop();
+								return;
+							}
+						}
+						nid = null;
+						fname = null;
+						flags = null;
 					}
-					if (i < actualLen) {
-						assert data[i] == '\n'; 
-						int nodeidLen = i - x < 40 ? i-x : 40; // if > 40, there are flags
-						DigestHelper.ascii2bin(data, x, nodeidLen, nodeidLookupBuffer); // ignore return value as it's unlikely to have NULL in manifest
-						nid = new Nodeid(nodeidLookupBuffer, false); // this Nodeid is for pool lookup only, mock object
-						Nodeid cached = nodeidPool.unify(nid);
-						if (cached == nid) {
-							// buffer now belongs to the cached nodeid
-							nodeidLookupBuffer = new byte[20];
-						} else {
-							nid = cached; // use existing version, discard the lookup object
-						} // for cpython 0..10k, cache hits are 15 973 301, vs 18871 misses.
-						thisRevPool.record(nid); // memorize revision for the next iteration. 
-						if (nodeidLen + x < i) {
-							// 'x' and 'l' for executable bits and symlinks?
-							// hg --debug manifest shows 644 for each regular file in my repo
-							// for cpython 0..10k, there are 4361062 flag checks, and there's only 1 unique flag
-							flags = Flags.parse(data, x + nodeidLen, i-x-nodeidLen);
-						} else {
-							flags = null;
-						}
-						boolean good2go;
-						if (inspector2 == null) {
-							String flagString = flags == null ? null : flags.nativeString();
-							good2go = inspector.next(nid, fname.toString(), flagString);
-						} else {
-							good2go = inspector2.next(nid, fname, flags);
-						}
-						if (!good2go) {
-							iterateControl.stop();
-							return;
-						}
-					}
-					nid = null;
-					fname = null;
-					flags = null;
 				}
 				if (!inspector.end(revisionNumber)) {
 					iterateControl.stop();
Binary file test-data/test-repos.jar has changed
--- a/test/org/tmatesoft/hg/test/TestStatus.java	Sat Dec 31 01:04:22 2011 +0300
+++ b/test/org/tmatesoft/hg/test/TestStatus.java	Fri Jan 06 00:42:15 2012 +0300
@@ -458,6 +458,23 @@
 
 	}
 	
+	/**
+	 * Issue 22
+	 */
+	@Test
+	public void testOnEmptyRepositoryWithAllFilesDeleted() throws Exception {
+		repo = Configuration.get().find("status-2");
+		HgStatusCommand cmd = new HgStatusCommand(repo);
+		cmd.all();
+		StatusCollector sc = new StatusCollector();
+		cmd.execute(sc);
+		// shall pass without exception
+		assertTrue(sc.getErrors().isEmpty());
+		for (HgStatus.Kind k : HgStatus.Kind.values()) {
+			assertTrue("Kind " + k.name() + " shall be empty",sc.get(k).isEmpty());
+		}
+	}
+	
 	/*
 	 * With warm-up of previous tests, 10 runs, time in milliseconds
 	 * 'hg status -A': Native client total 953 (95 per run), Java client 94 (9)