diff --git a/briar-core/src/org/briarproject/data/MetadataEncoderImpl.java b/briar-core/src/org/briarproject/data/MetadataEncoderImpl.java
index fc7dc3f9dc5a2808f71a993aa5984c2f1bf4eb99..f476df113476a9bf234c43a3891b9a28a5771d62 100644
--- a/briar-core/src/org/briarproject/data/MetadataEncoderImpl.java
+++ b/briar-core/src/org/briarproject/data/MetadataEncoderImpl.java
@@ -68,7 +68,7 @@ class MetadataEncoderImpl implements MetadataEncoder {
 
 	private void encodeInteger(ByteArrayOutputStream out, byte i) {
 		out.write(INT_8);
-		out.write(i);
+		encodeInt8(out, i);
 	}
 
 	private void encodeInteger(ByteArrayOutputStream out, short i) {
@@ -76,8 +76,7 @@ class MetadataEncoderImpl implements MetadataEncoder {
 			encodeInteger(out, (byte) i);
 		} else {
 			out.write(INT_16);
-			out.write((byte) (i >> 8));
-			out.write((byte) ((i << 8) >> 8));
+			encodeInt16(out, i);
 		}
 	}
 
@@ -86,10 +85,7 @@ class MetadataEncoderImpl implements MetadataEncoder {
 			encodeInteger(out, (short) i);
 		} else {
 			out.write(INT_32);
-			out.write((byte) (i >> 24));
-			out.write((byte) ((i << 8) >> 24));
-			out.write((byte) ((i << 16) >> 24));
-			out.write((byte) ((i << 24) >> 24));
+			encodeInt32(out, i);
 		}
 	}
 
@@ -98,24 +94,27 @@ class MetadataEncoderImpl implements MetadataEncoder {
 			encodeInteger(out, (int) i);
 		} else {
 			out.write(INT_64);
-			out.write((byte) (i >> 56));
-			out.write((byte) ((i << 8) >> 56));
-			out.write((byte) ((i << 16) >> 56));
-			out.write((byte) ((i << 24) >> 56));
-			out.write((byte) ((i << 32) >> 56));
-			out.write((byte) ((i << 40) >> 56));
-			out.write((byte) ((i << 48) >> 56));
-			out.write((byte) ((i << 56) >> 56));
+			encodeInt64(out, i);
 		}
 	}
 
-	private void encodeFloat(ByteArrayOutputStream out, float f) {
-		encodeFloat(out, (double) f);
+	private void encodeInt8(ByteArrayOutputStream out, byte i) {
+		out.write(i);
 	}
 
-	private void encodeFloat(ByteArrayOutputStream out, double d) {
-		long i = Double.doubleToLongBits(d);
-		out.write(FLOAT_64);
+	private void encodeInt16(ByteArrayOutputStream out, short i) {
+		out.write((byte) (i >> 8));
+		out.write((byte) ((i << 8) >> 8));
+	}
+
+	private void encodeInt32(ByteArrayOutputStream out, int i) {
+		out.write((byte) (i >> 24));
+		out.write((byte) ((i << 8) >> 24));
+		out.write((byte) ((i << 16) >> 24));
+		out.write((byte) ((i << 24) >> 24));
+	}
+
+	private void encodeInt64(ByteArrayOutputStream out, long i) {
 		out.write((byte) (i >> 56));
 		out.write((byte) ((i << 8) >> 56));
 		out.write((byte) ((i << 16) >> 56));
@@ -126,17 +125,26 @@ class MetadataEncoderImpl implements MetadataEncoder {
 		out.write((byte) ((i << 56) >> 56));
 	}
 
+	private void encodeFloat(ByteArrayOutputStream out, float f) {
+		encodeFloat(out, (double) f);
+	}
+
+	private void encodeFloat(ByteArrayOutputStream out, double d) {
+		out.write(FLOAT_64);
+		encodeInt64(out, Double.doubleToLongBits(d));
+	}
+
 	private void encodeString(ByteArrayOutputStream out, String s) {
 		byte[] b = StringUtils.toUtf8(s);
 		if (b.length <= Byte.MAX_VALUE) {
 			out.write(STRING_8);
-			encodeInteger(out, (byte) b.length);
+			encodeInt8(out, (byte) b.length);
 		} else if (b.length <= Short.MAX_VALUE) {
 			out.write(STRING_16);
-			encodeInteger(out, (short) b.length);
+			encodeInt16(out, (short) b.length);
 		} else {
 			out.write(STRING_32);
-			encodeInteger(out, b.length);
+			encodeInt32(out, b.length);
 		}
 		out.write(b, 0, b.length);
 	}
@@ -144,13 +152,13 @@ class MetadataEncoderImpl implements MetadataEncoder {
 	private void encodeRaw(ByteArrayOutputStream out, byte[] b) {
 		if (b.length <= Byte.MAX_VALUE) {
 			out.write(RAW_8);
-			encodeInteger(out, (byte) b.length);
+			encodeInt8(out, (byte) b.length);
 		} else if (b.length <= Short.MAX_VALUE) {
 			out.write(RAW_16);
-			encodeInteger(out, (short) b.length);
+			encodeInt16(out, (short) b.length);
 		} else {
 			out.write(RAW_32);
-			encodeInteger(out, b.length);
+			encodeInt32(out, b.length);
 		}
 		out.write(b, 0, b.length);
 	}
diff --git a/briar-core/src/org/briarproject/data/MetadataParserImpl.java b/briar-core/src/org/briarproject/data/MetadataParserImpl.java
index e4624dc6037881562a6ea7dff91a0c12ad9e076d..ce4c71a3a1f0b09b7872afb5f6a92be76f50f986 100644
--- a/briar-core/src/org/briarproject/data/MetadataParserImpl.java
+++ b/briar-core/src/org/briarproject/data/MetadataParserImpl.java
@@ -143,16 +143,18 @@ class MetadataParserImpl implements MetadataParser {
 
 	private BdfList parseList(ByteArrayInputStream in) throws FormatException {
 		BdfList list = new BdfList();
-		while (peek(in) != END) list.add(parseObject(in));
-		if (in.read() != END) throw new FormatException();
+		for (int b = peek(in); b != -1 && b != (END & 0xFF); b = peek(in))
+			list.add(parseObject(in));
+		if (in.read() != (END & 0xFF)) throw new FormatException();
 		return list;
 	}
 
 	private BdfDictionary parseDictionary(ByteArrayInputStream in)
 			throws FormatException {
 		BdfDictionary dict = new BdfDictionary();
-		while (peek(in) != END) dict.put(parseString(in), parseObject(in));
-		if (in.read() != END) throw new FormatException();
+		for (int b = peek(in); b != -1 && b != (END & 0xFF); b = peek(in))
+			dict.put(parseString(in), parseObject(in));
+		if (in.read() != (END & 0xFF)) throw new FormatException();
 		return dict;
 	}
 
diff --git a/briar-tests/src/org/briarproject/data/BdfReaderImplTest.java b/briar-tests/src/org/briarproject/data/BdfReaderImplTest.java
index 224ad0d9b5284991b60559ce7be2208e986e72f3..a0cef6a27e97532a45086bda5dd0888265f08250 100644
--- a/briar-tests/src/org/briarproject/data/BdfReaderImplTest.java
+++ b/briar-tests/src/org/briarproject/data/BdfReaderImplTest.java
@@ -258,6 +258,19 @@ public class BdfReaderImplTest extends BriarTestCase {
 		assertTrue(r.eof());
 	}
 
+	@Test
+	public void testReadUtf8String() throws Exception {
+		String str = "������ \uFDD0\uFDD1\uFDD2\uFDD3\uFDD1 ������";
+		String strHex = StringUtils.toHexString(str.getBytes("UTF-8"));
+		// STRING_8 tag, "foo", the empty string, and the test string
+		setContents("41" + "03" + "666F6F" + "41" + "00" +
+				"41" + "35" + strHex);
+		assertEquals("foo", r.readString(Integer.MAX_VALUE));
+		assertEquals("", r.readString(Integer.MAX_VALUE));
+		assertEquals(str, r.readString(Integer.MAX_VALUE));
+		assertTrue(r.eof());
+	}
+
 	@Test
 	public void testReadRaw8() throws Exception {
 		byte[] longest = new byte[Byte.MAX_VALUE];
diff --git a/briar-tests/src/org/briarproject/data/BdfWriterImplTest.java b/briar-tests/src/org/briarproject/data/BdfWriterImplTest.java
index 23fa9edec0590ad3b56ab4c472f54a2cd2306856..1d2b796461a88a3d2440056abb6eadc161f54de8 100644
--- a/briar-tests/src/org/briarproject/data/BdfWriterImplTest.java
+++ b/briar-tests/src/org/briarproject/data/BdfWriterImplTest.java
@@ -9,12 +9,11 @@ import org.junit.Test;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertArrayEquals;
 
 public class BdfWriterImplTest extends BriarTestCase {
 
@@ -113,6 +112,15 @@ public class BdfWriterImplTest extends BriarTestCase {
 		checkContents("44" + "00008000" + shortHex);
 	}
 
+	@Test
+	public void testWriteUtf8String() throws IOException {
+		String str = "������ \uFDD0\uFDD1\uFDD2\uFDD3\uFDD1 ������";
+		String strHex = StringUtils.toHexString(str.getBytes("UTF-8"));
+		w.writeString(str);
+		// STRING_8 tag, length 53, UTF-8 bytes
+		checkContents("41" + "35" + strHex);
+	}
+
 	@Test
 	public void testWriteBytes8() throws IOException {
 		byte[] longest = new byte[Byte.MAX_VALUE];
@@ -225,7 +233,7 @@ public class BdfWriterImplTest extends BriarTestCase {
 		out.flush();
 		out.close();
 		byte[] expected = StringUtils.fromHexString(hex);
-		assertTrue(StringUtils.toHexString(out.toByteArray()),
-				Arrays.equals(expected, out.toByteArray()));
+		assertArrayEquals(StringUtils.toHexString(out.toByteArray()),
+				expected, out.toByteArray());
 	}
 }
diff --git a/briar-tests/src/org/briarproject/data/MetadataEncoderImplTest.java b/briar-tests/src/org/briarproject/data/MetadataEncoderImplTest.java
deleted file mode 100644
index c0ab879def193ba9de00e83b6e758ef65b64c34d..0000000000000000000000000000000000000000
--- a/briar-tests/src/org/briarproject/data/MetadataEncoderImplTest.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.briarproject.data;
-
-import org.briarproject.BriarTestCase;
-import org.junit.Test;
-
-import static org.junit.Assert.fail;
-
-public class MetadataEncoderImplTest extends BriarTestCase {
-
-	@Test
-	public void testUnitTestsExist() {
-		fail(); // FIXME: Write tests
-	}
-}
diff --git a/briar-tests/src/org/briarproject/data/MetadataEncoderParserImplTest.java b/briar-tests/src/org/briarproject/data/MetadataEncoderParserImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f518e0d6175513e2cc6a1815cbe8c2798261a033
--- /dev/null
+++ b/briar-tests/src/org/briarproject/data/MetadataEncoderParserImplTest.java
@@ -0,0 +1,158 @@
+package org.briarproject.data;
+
+import org.briarproject.BriarTestCase;
+import org.briarproject.api.FormatException;
+import org.briarproject.api.data.BdfDictionary;
+import org.briarproject.api.db.Metadata;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+public class MetadataEncoderParserImplTest extends BriarTestCase {
+
+	MetadataEncoderImpl e = new MetadataEncoderImpl();
+	MetadataParserImpl p = new MetadataParserImpl();
+	BdfDictionary d = new BdfDictionary();
+
+	@Test
+	public void testBoolean() throws FormatException {
+		d.put("test", true);
+		Metadata metadata = e.encode(d);
+
+		assertEquals(true, p.parse(metadata).getBoolean("test", false));
+	}
+
+	@Test
+	public void testInteger() throws FormatException {
+		d.put("test", 1337);
+		Metadata metadata = e.encode(d);
+
+		assertEquals(1337L, (long) p.parse(metadata).getInteger("test", 0L));
+	}
+
+	@Test
+	public void testLong() throws FormatException {
+		d.put("test", Long.MAX_VALUE);
+		Metadata metadata = e.encode(d);
+
+		assertEquals(Long.MAX_VALUE,
+				(long) p.parse(metadata).getInteger("test", 0L));
+	}
+
+	@Test
+	public void testDouble() throws FormatException {
+		d.put("test", Double.MAX_VALUE);
+		Metadata metadata = e.encode(d);
+
+		assertEquals(Double.MAX_VALUE,
+				p.parse(metadata).getFloat("test", 0.0), 0);
+	}
+
+	@Test
+	public void testFloat() throws FormatException {
+		d.put("test", Float.MIN_NORMAL);
+		Metadata metadata = e.encode(d);
+
+		assertEquals(Float.MIN_NORMAL,
+				p.parse(metadata).getFloat("test", 0.0), 0);
+	}
+
+	@Test
+	public void testString() throws FormatException {
+		d.put("test", "abc");
+		Metadata metadata = e.encode(d);
+
+		assertEquals("abc", p.parse(metadata).getString("test", null));
+	}
+
+	@Test
+	public void testUtf8String() throws FormatException {
+		d.put("test", "abcdefghilkmnopqrst ������ \uFDD0\uFDD1\uFDD2\uFDD3");
+		Metadata metadata = e.encode(d);
+
+		assertEquals("abcdefghilkmnopqrst ������ \uFDD0\uFDD1\uFDD2\uFDD3",
+				p.parse(metadata).getString("test", null));
+	}
+
+	@Test
+	public void testRaw() throws FormatException {
+		byte[] b = "\uFDD0\uFDD1\uFDD2\uFDD3".getBytes();
+		d.put("test", b);
+		Metadata metadata = e.encode(d);
+
+		assertArrayEquals(b, p.parse(metadata).getRaw("test", null));
+	}
+
+	@Test
+	public void testList() throws FormatException {
+		List<Long> l = new ArrayList<Long>(4);
+		l.add(42L);
+		l.add(1337L);
+		l.add(Long.MIN_VALUE);
+		l.add(Long.MAX_VALUE);
+
+		d.put("test", l);
+		Metadata metadata = e.encode(d);
+
+		assertArrayEquals(l.toArray(),
+				p.parse(metadata).getList("test", null).toArray());
+	}
+
+	@Test
+	public void testDictionary() throws FormatException {
+		Map<String, Boolean> m = new HashMap<String, Boolean>();
+		m.put("1", true);
+		m.put("2", false);
+
+		d.put("test", m);
+		Metadata metadata = e.encode(d);
+
+		assertEquals(true, p.parse(metadata).getDictionary("test", null)
+				.getBoolean("1", false));
+
+		assertEquals(false, p.parse(metadata).getDictionary("test", null)
+				.getBoolean("2", true));
+	}
+
+	@Test
+	public void testComplexDictionary() throws FormatException {
+		Map<String, List> m = new HashMap<String, List>();
+		List<String> one = new ArrayList<String>(3);
+		one.add("����");
+		one.add("������");
+		one.add("����");
+		m.put("One", one);
+		List<String> two = new ArrayList<String>(2);
+		two.add("\u0080");
+		two.add("\uD800\uDC00");
+		m.put("Two", two);
+		d.put("test", m);
+
+		Map<String, Boolean> m2 = new HashMap<String, Boolean>();
+		m2.put("should be true", true);
+		d.put("another test", m2);
+
+		Metadata metadata = e.encode(d);
+
+		assertEquals("����", p.parse(metadata).getDictionary("test", null)
+				.getList("One", null).get(0));
+		assertEquals("������", p.parse(metadata).getDictionary("test", null)
+				.getList("One", null).get(1));
+		assertEquals("����", p.parse(metadata).getDictionary("test", null)
+				.getList("One", null).get(2));
+		assertEquals("\u0080", p.parse(metadata).getDictionary("test", null)
+				.getList("Two", null).get(0));
+		assertEquals("\uD800\uDC00", p.parse(metadata).getDictionary("test", null)
+				.getList("Two", null).get(1));
+
+		assertEquals(true, p.parse(metadata).getDictionary("another test", null)
+				.getBoolean("should be true", false));
+	}
+
+}
diff --git a/briar-tests/src/org/briarproject/data/MetadataParserImplTest.java b/briar-tests/src/org/briarproject/data/MetadataParserImplTest.java
deleted file mode 100644
index 5e3518fb509cc41e266048c9eef7356a29cccd61..0000000000000000000000000000000000000000
--- a/briar-tests/src/org/briarproject/data/MetadataParserImplTest.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.briarproject.data;
-
-import org.briarproject.BriarTestCase;
-import org.junit.Test;
-
-import static org.junit.Assert.fail;
-
-public class MetadataParserImplTest extends BriarTestCase {
-
-	@Test
-	public void testUnitTestsExist() {
-		fail(); // FIXME: Write tests
-	}
-}