diff --git a/briar-tests/build.xml b/briar-tests/build.xml
index 5211bfe17a4155d886d6c682302df3824df0f155..8bbb88e7d7b34823b21c5735759142ccf23c37d9 100644
--- a/briar-tests/build.xml
+++ b/briar-tests/build.xml
@@ -88,12 +88,10 @@
 			<test name='net.sf.briar.plugins.modem.CountryCodesTest'/>
 			<test name='net.sf.briar.plugins.modem.ModemPluginTest'/>
 			<test name='net.sf.briar.plugins.tcp.LanTcpPluginTest'/>
-			<test name='net.sf.briar.protocol.AckReaderTest'/>
 			<test name='net.sf.briar.protocol.ConstantsTest'/>
 			<test name='net.sf.briar.protocol.ConsumersTest'/>
-			<test name='net.sf.briar.protocol.OfferReaderTest'/>
+			<test name='net.sf.briar.protocol.ProtocolReaderImplTest'/>
 			<test name='net.sf.briar.protocol.ProtocolWriterImplTest'/>
-			<test name='net.sf.briar.protocol.RequestReaderTest'/>
 			<test name='net.sf.briar.protocol.simplex.OutgoingSimplexConnectionTest'/>
 			<test name='net.sf.briar.protocol.simplex.SimplexProtocolIntegrationTest'/>
 			<test name='net.sf.briar.serial.ReaderImplTest'/>
diff --git a/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java b/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java
index abca57ba327544495e69b8178ac498dbb5115633..5abda455f96690a371d5f4602e0cf0b6f56ae2ac 100644
--- a/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java
+++ b/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java
@@ -15,6 +15,7 @@ import java.util.Collections;
 import java.util.Random;
 
 import net.sf.briar.api.ContactId;
+import net.sf.briar.api.TransportProperties;
 import net.sf.briar.api.crypto.CryptoComponent;
 import net.sf.briar.api.protocol.Ack;
 import net.sf.briar.api.protocol.Author;
@@ -64,7 +65,6 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 	private final MessageVerifier messageVerifier;
 
 	private final ContactId contactId;
-	private final TransportId transportId;
 	private final byte[] secret;
 	private final Author author;
 	private final Group group, group1;
@@ -73,7 +73,8 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 	private final String subject = "Hello";
 	private final String messageBody = "Hello world";
 	private final Collection<MessageId> messageIds;
-	private final Collection<Transport> transports;
+	private final TransportId transportId;
+	private final TransportProperties transportProperties;
 
 	public ProtocolIntegrationTest() throws Exception {
 		super();
@@ -88,7 +89,6 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 		protocolWriterFactory = i.getInstance(ProtocolWriterFactory.class);
 		messageVerifier = i.getInstance(MessageVerifier.class);
 		contactId = new ContactId(234);
-		transportId = new TransportId(TestUtils.getRandomId());
 		// Create a shared secret
 		secret = new byte[32];
 		new Random().nextBytes(secret);
@@ -119,11 +119,10 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 				subject, messageBody.getBytes("UTF-8"));
 		messageIds = Arrays.asList(message.getId(),
 				message1.getId(), message2.getId(), message3.getId());
-		// Create some transports
-		TransportId transportId = new TransportId(TestUtils.getRandomId());
-		Transport transport = new Transport(transportId,
-				Collections.singletonMap("bar", "baz"));
-		transports = Collections.singletonList(transport);
+		// Create some transport properties
+		transportId = new TransportId(TestUtils.getRandomId());
+		transportProperties = new TransportProperties(Collections.singletonMap(
+				"bar", "baz"));
 	}
 
 	@Test
@@ -155,16 +154,13 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 		requested.set(3);
 		writer.writeRequest(new Request(requested, 4));
 
-		Collection<SubscriptionHole> holes = Arrays.asList(
-				new SubscriptionHole(group.getId(), group1.getId()));
-		Collection<Subscription> subs = Arrays.asList(
-				new Subscription(group, 0L), new Subscription(group1, 0L));
-		SubscriptionUpdate s = new SubscriptionUpdate(holes, subs, 0L,
-				subscriptionVersion);
-		writer.writeSubscriptionUpdate(s);
+		SubscriptionUpdate su = new SubscriptionUpdate(
+				Arrays.asList(group, group1), 1L);
+		writer.writeSubscriptionUpdate(su);
 
-		TransportUpdate t = new TransportUpdate(transports, transportVersion);
-		writer.writeTransportUpdate(t);
+		TransportUpdate tu = new TransportUpdate(transportId,
+				transportProperties, 1L);
+		writer.writeTransportUpdate(tu);
 
 		writer.flush();
 		return out.toByteArray();
@@ -219,13 +215,16 @@ public class ProtocolIntegrationTest extends BriarTestCase {
 
 		// Read the subscription update
 		assertTrue(reader.hasSubscriptionUpdate());
-		SubscriptionUpdate s = reader.readSubscriptionUpdate();
-		// FIXME: Test for equality
+		SubscriptionUpdate su = reader.readSubscriptionUpdate();
+		assertEquals(Arrays.asList(group, group1), su.getGroups());
+		assertEquals(1L, su.getVersion());
 
 		// Read the transport update
 		assertTrue(reader.hasTransportUpdate());
-		TransportUpdate t = reader.readTransportUpdate();
-		// FIXME: Test for equality
+		TransportUpdate tu = reader.readTransportUpdate();
+		assertEquals(transportId, tu.getId());
+		assertEquals(transportProperties, tu.getProperties());
+		assertEquals(1L, tu.getVersion());
 
 		in.close();
 	}
diff --git a/briar-tests/src/net/sf/briar/protocol/AckReaderTest.java b/briar-tests/src/net/sf/briar/protocol/AckReaderTest.java
deleted file mode 100644
index 82f792ab2ecc81d135538a60b2c48a800240afa0..0000000000000000000000000000000000000000
--- a/briar-tests/src/net/sf/briar/protocol/AckReaderTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package net.sf.briar.protocol;
-
-import static net.sf.briar.api.protocol.ProtocolConstants.MAX_PACKET_LENGTH;
-import static net.sf.briar.api.protocol.Types.ACK;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-
-import net.sf.briar.BriarTestCase;
-import net.sf.briar.TestUtils;
-import net.sf.briar.api.FormatException;
-import net.sf.briar.api.protocol.Ack;
-import net.sf.briar.api.serial.Reader;
-import net.sf.briar.api.serial.ReaderFactory;
-import net.sf.briar.api.serial.SerialComponent;
-import net.sf.briar.api.serial.Writer;
-import net.sf.briar.api.serial.WriterFactory;
-import net.sf.briar.serial.SerialModule;
-
-import org.junit.Test;
-
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-
-public class AckReaderTest extends BriarTestCase {
-
-	// FIXME: This is an integration test, not a unit test
-
-	private final SerialComponent serial;
-	private final ReaderFactory readerFactory;
-	private final WriterFactory writerFactory;
-
-	public AckReaderTest() throws Exception {
-		super();
-		Injector i = Guice.createInjector(new SerialModule());
-		serial = i.getInstance(SerialComponent.class);
-		readerFactory = i.getInstance(ReaderFactory.class);
-		writerFactory = i.getInstance(WriterFactory.class);
-	}
-
-	@Test
-	public void testFormatExceptionIfAckIsTooLarge() throws Exception {
-		byte[] b = createAck(true);
-		ByteArrayInputStream in = new ByteArrayInputStream(b);
-		Reader reader = readerFactory.createReader(in);
-		reader.addStructReader(ACK, new AckReader());
-		try {
-			reader.readStruct(ACK, Ack.class);
-			fail();
-		} catch(FormatException expected) {}
-	}
-
-	@Test
-	public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception {
-		byte[] b = createAck(false);
-		ByteArrayInputStream in = new ByteArrayInputStream(b);
-		Reader reader = readerFactory.createReader(in);
-		reader.addStructReader(ACK, new AckReader());
-		reader.readStruct(ACK, Ack.class);
-	}
-
-	@Test
-	public void testEmptyAck() throws Exception {
-		byte[] b = createEmptyAck();
-		ByteArrayInputStream in = new ByteArrayInputStream(b);
-		Reader reader = readerFactory.createReader(in);
-		reader.addStructReader(ACK, new AckReader());
-		try {
-			reader.readStruct(ACK, Ack.class);
-			fail();
-		} catch(FormatException expected) {}
-	}
-
-	private byte[] createAck(boolean tooBig) throws Exception {
-		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		Writer w = writerFactory.createWriter(out);
-		w.writeStructId(ACK);
-		w.writeListStart();
-		while(out.size() + serial.getSerialisedUniqueIdLength()
-				< MAX_PACKET_LENGTH) {
-			w.writeBytes(TestUtils.getRandomId());
-		}
-		if(tooBig) w.writeBytes(TestUtils.getRandomId());
-		w.writeListEnd();
-		assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH);
-		return out.toByteArray();
-	}
-
-	private byte[] createEmptyAck() throws Exception {
-		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		Writer w = writerFactory.createWriter(out);
-		w.writeStructId(ACK);
-		w.writeListStart();
-		w.writeListEnd();
-		return out.toByteArray();
-	}
-}
diff --git a/briar-tests/src/net/sf/briar/protocol/OfferReaderTest.java b/briar-tests/src/net/sf/briar/protocol/OfferReaderTest.java
deleted file mode 100644
index e10da58b0d12dd682c0b104015eedd946e825f9f..0000000000000000000000000000000000000000
--- a/briar-tests/src/net/sf/briar/protocol/OfferReaderTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package net.sf.briar.protocol;
-
-import static net.sf.briar.api.protocol.ProtocolConstants.MAX_PACKET_LENGTH;
-import static net.sf.briar.api.protocol.Types.OFFER;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-
-import net.sf.briar.BriarTestCase;
-import net.sf.briar.TestUtils;
-import net.sf.briar.api.FormatException;
-import net.sf.briar.api.protocol.Offer;
-import net.sf.briar.api.serial.Reader;
-import net.sf.briar.api.serial.ReaderFactory;
-import net.sf.briar.api.serial.SerialComponent;
-import net.sf.briar.api.serial.Writer;
-import net.sf.briar.api.serial.WriterFactory;
-import net.sf.briar.serial.SerialModule;
-
-import org.junit.Test;
-
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-
-public class OfferReaderTest extends BriarTestCase {
-
-	// FIXME: This is an integration test, not a unit test
-
-	private final SerialComponent serial;
-	private final ReaderFactory readerFactory;
-	private final WriterFactory writerFactory;
-
-	public OfferReaderTest() throws Exception {
-		super();
-		Injector i = Guice.createInjector(new SerialModule());
-		serial = i.getInstance(SerialComponent.class);
-		readerFactory = i.getInstance(ReaderFactory.class);
-		writerFactory = i.getInstance(WriterFactory.class);
-	}
-
-	@Test
-	public void testFormatExceptionIfOfferIsTooLarge() throws Exception {
-		byte[] b = createOffer(true);
-		ByteArrayInputStream in = new ByteArrayInputStream(b);
-		Reader reader = readerFactory.createReader(in);
-		reader.addStructReader(OFFER, new OfferReader());
-		try {
-			reader.readStruct(OFFER, Offer.class);
-			fail();
-		} catch(FormatException expected) {}
-	}
-
-	@Test
-	public void testNoFormatExceptionIfOfferIsMaximumSize() throws Exception {
-		byte[] b = createOffer(false);
-		ByteArrayInputStream in = new ByteArrayInputStream(b);
-		Reader reader = readerFactory.createReader(in);
-		reader.addStructReader(OFFER, new OfferReader());
-		reader.readStruct(OFFER, Offer.class);
-	}
-
-	@Test
-	public void testEmptyOffer() throws Exception {
-		byte[] b = createEmptyOffer();
-		ByteArrayInputStream in = new ByteArrayInputStream(b);
-		Reader reader = readerFactory.createReader(in);
-		reader.addStructReader(OFFER, new OfferReader());
-		try {
-			reader.readStruct(OFFER, Offer.class);
-			fail();
-		} catch(FormatException expected) {}
-	}
-
-	private byte[] createOffer(boolean tooBig) throws Exception {
-		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		Writer w = writerFactory.createWriter(out);
-		w.writeStructId(OFFER);
-		w.writeListStart();
-		while(out.size() + serial.getSerialisedUniqueIdLength()
-				< MAX_PACKET_LENGTH) {
-			w.writeBytes(TestUtils.getRandomId());
-		}
-		if(tooBig) w.writeBytes(TestUtils.getRandomId());
-		w.writeListEnd();
-		assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH);
-		return out.toByteArray();
-	}
-
-	private byte[] createEmptyOffer() throws Exception {
-		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		Writer w = writerFactory.createWriter(out);
-		w.writeStructId(OFFER);
-		w.writeListStart();
-		w.writeListEnd();
-		return out.toByteArray();
-	}
-}
diff --git a/briar-tests/src/net/sf/briar/protocol/ProtocolReaderImplTest.java b/briar-tests/src/net/sf/briar/protocol/ProtocolReaderImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..15339e20baeeeba69184530f2cc6c686f4422b3f
--- /dev/null
+++ b/briar-tests/src/net/sf/briar/protocol/ProtocolReaderImplTest.java
@@ -0,0 +1,238 @@
+package net.sf.briar.protocol;
+
+import static net.sf.briar.api.protocol.ProtocolConstants.MAX_PACKET_LENGTH;
+import static net.sf.briar.api.protocol.Types.ACK;
+import static net.sf.briar.api.protocol.Types.OFFER;
+import static net.sf.briar.api.protocol.Types.REQUEST;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.BitSet;
+
+import net.sf.briar.BriarTestCase;
+import net.sf.briar.TestUtils;
+import net.sf.briar.api.FormatException;
+import net.sf.briar.api.protocol.Request;
+import net.sf.briar.api.serial.ReaderFactory;
+import net.sf.briar.api.serial.SerialComponent;
+import net.sf.briar.api.serial.Writer;
+import net.sf.briar.api.serial.WriterFactory;
+import net.sf.briar.serial.SerialModule;
+
+import org.junit.Test;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+public class ProtocolReaderImplTest extends BriarTestCase {
+
+	// FIXME: This is an integration test, not a unit test
+
+	private final SerialComponent serial;
+	private final ReaderFactory readerFactory;
+	private final WriterFactory writerFactory;
+
+	public ProtocolReaderImplTest() throws Exception {
+		super();
+		Injector i = Guice.createInjector(new SerialModule());
+		serial = i.getInstance(SerialComponent.class);
+		readerFactory = i.getInstance(ReaderFactory.class);
+		writerFactory = i.getInstance(WriterFactory.class);
+	}
+
+	@Test
+	public void testFormatExceptionIfAckIsTooLarge() throws Exception {
+		byte[] b = createAck(true);
+		ByteArrayInputStream in = new ByteArrayInputStream(b);
+		ProtocolReaderImpl reader = new ProtocolReaderImpl(readerFactory, null,
+				null, in);
+		try {
+			reader.readAck();
+			fail();
+		} catch(FormatException expected) {}
+	}
+
+	@Test
+	public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception {
+		byte[] b = createAck(false);
+		ByteArrayInputStream in = new ByteArrayInputStream(b);
+		ProtocolReaderImpl reader = new ProtocolReaderImpl(readerFactory, null,
+				null, in);
+		reader.readAck();
+	}
+
+	@Test
+	public void testEmptyAck() throws Exception {
+		byte[] b = createEmptyAck();
+		ByteArrayInputStream in = new ByteArrayInputStream(b);
+		ProtocolReaderImpl reader = new ProtocolReaderImpl(readerFactory, null,
+				null, in);
+		try {
+			reader.readAck();
+			fail();
+		} catch(FormatException expected) {}
+	}
+
+	@Test
+	public void testFormatExceptionIfOfferIsTooLarge() throws Exception {
+		byte[] b = createOffer(true);
+		ByteArrayInputStream in = new ByteArrayInputStream(b);
+		ProtocolReaderImpl reader = new ProtocolReaderImpl(readerFactory, null,
+				null, in);
+		try {
+			reader.readOffer();
+			fail();
+		} catch(FormatException expected) {}
+	}
+
+	@Test
+	public void testNoFormatExceptionIfOfferIsMaximumSize() throws Exception {
+		byte[] b = createOffer(false);
+		ByteArrayInputStream in = new ByteArrayInputStream(b);
+		ProtocolReaderImpl reader = new ProtocolReaderImpl(readerFactory, null,
+				null, in);
+		reader.readOffer();
+	}
+
+	@Test
+	public void testEmptyOffer() throws Exception {
+		byte[] b = createEmptyOffer();
+		ByteArrayInputStream in = new ByteArrayInputStream(b);
+		ProtocolReaderImpl reader = new ProtocolReaderImpl(readerFactory, null,
+				null, in);
+		try {
+			reader.readOffer();
+			fail();
+		} catch(FormatException expected) {}
+	}
+
+	@Test
+	public void testFormatExceptionIfRequestIsTooLarge() throws Exception {
+		byte[] b = createRequest(true);
+		ByteArrayInputStream in = new ByteArrayInputStream(b);
+		ProtocolReaderImpl reader = new ProtocolReaderImpl(readerFactory, null,
+				null, in);
+		try {
+			reader.readRequest();
+			fail();
+		} catch(FormatException expected) {}
+	}
+
+	@Test
+	public void testNoFormatExceptionIfRequestIsMaximumSize() throws Exception {
+		byte[] b = createRequest(false);
+		ByteArrayInputStream in = new ByteArrayInputStream(b);
+		ProtocolReaderImpl reader = new ProtocolReaderImpl(readerFactory, null,
+				null, in);
+		reader.readRequest();
+	}
+
+	@Test
+	public void testBitmapDecoding() throws Exception {
+		// Test sizes from 0 to 1000 bits
+		for(int i = 0; i < 1000; i++) {
+			// Create a BitSet of size i with one in ten bits set (on average)
+			BitSet requested = new BitSet(i);
+			for(int j = 0; j < i; j++) if(Math.random() < 0.1) requested.set(j);
+			// Encode the BitSet as a bitmap
+			int bytes = i % 8 == 0 ? i / 8 : i / 8 + 1;
+			byte[] bitmap = new byte[bytes];
+			for(int j = 0; j < i; j++) {
+				if(requested.get(j)) {
+					int offset = j / 8;
+					byte bit = (byte) (128 >> j % 8);
+					bitmap[offset] |= bit;
+				}
+			}
+			// Create a serialised request containing the bitmap
+			byte[] b = createRequest(bitmap);
+			// Deserialise the request
+			ByteArrayInputStream in = new ByteArrayInputStream(b);
+			ProtocolReaderImpl reader = new ProtocolReaderImpl(readerFactory,
+					null, null, in);
+			Request request = reader.readRequest();
+			BitSet decoded = request.getBitmap();
+			// Check that the decoded BitSet matches the original - we can't
+			// use equals() because of padding, but the first i bits should
+			// match and the cardinalities should be equal, indicating that no
+			// padding bits are set
+			for(int j = 0; j < i; j++) {
+				assertEquals(requested.get(j), decoded.get(j));
+			}
+			assertEquals(requested.cardinality(), decoded.cardinality());
+		}
+	}
+
+	private byte[] createAck(boolean tooBig) throws Exception {
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		Writer w = writerFactory.createWriter(out);
+		w.writeStructId(ACK);
+		w.writeListStart();
+		while(out.size() + serial.getSerialisedUniqueIdLength()
+				< MAX_PACKET_LENGTH) {
+			w.writeBytes(TestUtils.getRandomId());
+		}
+		if(tooBig) w.writeBytes(TestUtils.getRandomId());
+		w.writeListEnd();
+		assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH);
+		return out.toByteArray();
+	}
+
+	private byte[] createEmptyAck() throws Exception {
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		Writer w = writerFactory.createWriter(out);
+		w.writeStructId(ACK);
+		w.writeListStart();
+		w.writeListEnd();
+		return out.toByteArray();
+	}
+
+	private byte[] createOffer(boolean tooBig) throws Exception {
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		Writer w = writerFactory.createWriter(out);
+		w.writeStructId(OFFER);
+		w.writeListStart();
+		while(out.size() + serial.getSerialisedUniqueIdLength()
+				< MAX_PACKET_LENGTH) {
+			w.writeBytes(TestUtils.getRandomId());
+		}
+		if(tooBig) w.writeBytes(TestUtils.getRandomId());
+		w.writeListEnd();
+		assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH);
+		return out.toByteArray();
+	}
+
+	private byte[] createEmptyOffer() throws Exception {
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		Writer w = writerFactory.createWriter(out);
+		w.writeStructId(OFFER);
+		w.writeListStart();
+		w.writeListEnd();
+		return out.toByteArray();
+	}
+
+	private byte[] createRequest(boolean tooBig) throws Exception {
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		Writer w = writerFactory.createWriter(out);
+		w.writeStructId(REQUEST);
+		// Allow one byte for the REQUEST tag, one byte for the padding length
+		// as a uint7, one byte for the BYTES tag, and five bytes for the
+		// length of the byte array as an int32
+		int size = MAX_PACKET_LENGTH - 8;
+		if(tooBig) size++;
+		assertTrue(size > Short.MAX_VALUE);
+		w.writeUint7((byte) 0);
+		w.writeBytes(new byte[size]);
+		assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH);
+		return out.toByteArray();
+	}
+
+	private byte[] createRequest(byte[] bitmap) throws Exception {
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		Writer w = writerFactory.createWriter(out);
+		w.writeStructId(REQUEST);
+		w.writeUint7((byte) 0);
+		w.writeBytes(bitmap);
+		return out.toByteArray();
+	}
+}
diff --git a/briar-tests/src/net/sf/briar/protocol/RequestReaderTest.java b/briar-tests/src/net/sf/briar/protocol/RequestReaderTest.java
deleted file mode 100644
index ec9d2746d449907dd4c33d3565c2951cf72f9bfe..0000000000000000000000000000000000000000
--- a/briar-tests/src/net/sf/briar/protocol/RequestReaderTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package net.sf.briar.protocol;
-
-import static net.sf.briar.api.protocol.ProtocolConstants.MAX_PACKET_LENGTH;
-import static net.sf.briar.api.protocol.Types.REQUEST;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.util.BitSet;
-
-import net.sf.briar.BriarTestCase;
-import net.sf.briar.api.FormatException;
-import net.sf.briar.api.protocol.Request;
-import net.sf.briar.api.serial.Reader;
-import net.sf.briar.api.serial.ReaderFactory;
-import net.sf.briar.api.serial.Writer;
-import net.sf.briar.api.serial.WriterFactory;
-import net.sf.briar.clock.ClockModule;
-import net.sf.briar.crypto.CryptoModule;
-import net.sf.briar.serial.SerialModule;
-
-import org.junit.Test;
-
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-
-public class RequestReaderTest extends BriarTestCase {
-
-	// FIXME: This is an integration test, not a unit test
-
-	private final ReaderFactory readerFactory;
-	private final WriterFactory writerFactory;
-
-	public RequestReaderTest() throws Exception {
-		super();
-		Injector i = Guice.createInjector(new ClockModule(), new CryptoModule(),
-				new ProtocolModule(), new SerialModule());
-		readerFactory = i.getInstance(ReaderFactory.class);
-		writerFactory = i.getInstance(WriterFactory.class);
-	}
-
-	@Test
-	public void testFormatExceptionIfRequestIsTooLarge() throws Exception {
-		byte[] b = createRequest(true);
-		ByteArrayInputStream in = new ByteArrayInputStream(b);
-		Reader reader = readerFactory.createReader(in);
-		reader.addStructReader(REQUEST, new RequestReader());
-		try {
-			reader.readStruct(REQUEST, Request.class);
-			fail();
-		} catch(FormatException expected) {}
-	}
-
-	@Test
-	public void testNoFormatExceptionIfRequestIsMaximumSize() throws Exception {
-		byte[] b = createRequest(false);
-		ByteArrayInputStream in = new ByteArrayInputStream(b);
-		Reader reader = readerFactory.createReader(in);
-		reader.addStructReader(REQUEST, new RequestReader());
-		reader.readStruct(REQUEST, Request.class);
-	}
-
-	@Test
-	public void testBitmapDecoding() throws Exception {
-		// Test sizes from 0 to 1000 bits
-		for(int i = 0; i < 1000; i++) {
-			// Create a BitSet of size i with one in ten bits set (on average)
-			BitSet requested = new BitSet(i);
-			for(int j = 0; j < i; j++) if(Math.random() < 0.1) requested.set(j);
-			// Encode the BitSet as a bitmap
-			int bytes = i % 8 == 0 ? i / 8 : i / 8 + 1;
-			byte[] bitmap = new byte[bytes];
-			for(int j = 0; j < i; j++) {
-				if(requested.get(j)) {
-					int offset = j / 8;
-					byte bit = (byte) (128 >> j % 8);
-					bitmap[offset] |= bit;
-				}
-			}
-			// Create a serialised request containing the bitmap
-			byte[] b = createRequest(bitmap);
-			// Deserialise the request
-			ByteArrayInputStream in = new ByteArrayInputStream(b);
-			Reader reader = readerFactory.createReader(in);
-			RequestReader requestReader = new RequestReader();
-			reader.addStructReader(REQUEST, requestReader);
-			Request r = reader.readStruct(REQUEST, Request.class);
-			BitSet decoded = r.getBitmap();
-			// Check that the decoded BitSet matches the original - we can't
-			// use equals() because of padding, but the first i bits should
-			// match and the cardinalities should be equal, indicating that no
-			// padding bits are set
-			for(int j = 0; j < i; j++) {
-				assertEquals(requested.get(j), decoded.get(j));
-			}
-			assertEquals(requested.cardinality(), decoded.cardinality());
-		}
-	}
-
-	private byte[] createRequest(boolean tooBig) throws Exception {
-		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		Writer w = writerFactory.createWriter(out);
-		w.writeStructId(REQUEST);
-		// Allow one byte for the REQUEST tag, one byte for the padding length
-		// as a uint7, one byte for the BYTES tag, and five bytes for the
-		// length of the byte array as an int32
-		int size = MAX_PACKET_LENGTH - 8;
-		if(tooBig) size++;
-		assertTrue(size > Short.MAX_VALUE);
-		w.writeUint7((byte) 0);
-		w.writeBytes(new byte[size]);
-		assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH);
-		return out.toByteArray();
-	}
-
-	private byte[] createRequest(byte[] bitmap) throws Exception {
-		ByteArrayOutputStream out = new ByteArrayOutputStream();
-		Writer w = writerFactory.createWriter(out);
-		w.writeStructId(REQUEST);
-		w.writeUint7((byte) 0);
-		w.writeBytes(bitmap);
-		return out.toByteArray();
-	}
-}