Index: test/org/openstreetmap/josm/gui/annotation/AnnotationPresetTest.java
===================================================================
--- test/org/openstreetmap/josm/gui/annotation/AnnotationPresetTest.java	(revision 193)
+++ test/org/openstreetmap/josm/gui/annotation/AnnotationPresetTest.java	(revision 193)
@@ -0,0 +1,57 @@
+package org.openstreetmap.josm.gui.annotation;
+
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.util.List;
+
+import javax.swing.Action;
+
+import junit.framework.TestCase;
+
+import org.openstreetmap.josm.gui.annotation.AnnotationPreset.Check;
+import org.openstreetmap.josm.gui.annotation.AnnotationPreset.Combo;
+import org.openstreetmap.josm.gui.annotation.AnnotationPreset.Key;
+import org.openstreetmap.josm.gui.annotation.AnnotationPreset.Label;
+import org.openstreetmap.josm.gui.annotation.AnnotationPreset.Text;
+
+public class AnnotationPresetTest extends TestCase {
+
+	public void testAnnotationPresetLoads() throws Exception {
+		InputStream in = getClass().getResourceAsStream("annotation-test.xml");
+		List<AnnotationPreset> all = AnnotationPreset.readAll(in);
+
+		assertEquals(1, all.size());
+		AnnotationPreset a = all.get(0);
+		assertEquals("Highway", a.getValue(Action.NAME));
+		Field dataField = a.getClass().getDeclaredField("data");
+		dataField.setAccessible(true);
+		List<?> data = (List<?>)dataField.get(a);
+		assertEquals(5, data.size());
+
+		Label label = (Label)data.get(0);
+		assertEquals("Inserting a highway in UK", label.text);
+
+		Text text = (Text)data.get(1);
+		assertEquals("name", text.key);
+		assertEquals("Highway (e.g. M3)", text.text);
+		assertFalse(text.delete_if_empty);
+		assertNull(text.default_);
+
+		Combo combo = (Combo)data.get(2);
+		assertEquals("highway", combo.key);
+		assertEquals("Type", combo.text);
+		assertEquals("major,minor", combo.values);
+		assertTrue(combo.delete_if_empty);
+		assertTrue(combo.editable);
+		assertNull(combo.default_);
+
+		Check check = (Check)data.get(3);
+		assertEquals("oneway", check.key);
+		assertEquals("Oneway", check.text);
+		assertTrue(check.default_);
+
+		Key key = (Key)data.get(4);
+		assertEquals("class", key.key);
+		assertEquals("highway", key.value);
+	}
+}
Index: test/org/openstreetmap/josm/gui/annotation/annotation-test.xml
===================================================================
--- test/org/openstreetmap/josm/gui/annotation/annotation-test.xml	(revision 193)
+++ test/org/openstreetmap/josm/gui/annotation/annotation-test.xml	(revision 193)
@@ -0,0 +1,14 @@
+<annotations>
+  <item name="Highway">
+    <label text="Inserting a highway in UK" />
+
+    <text key="name" text="Highway (e.g. M3)" />
+    <combo key="highway" text="Type" values="major,minor" delete_if_empty="true" />
+
+    <!-- Highways are usually oneway -->
+    <check key="oneway" text="Oneway" default="on" />
+
+    <!-- Always setting class=highway -->
+    <key key="class" value="highway" />
+  </item>
+</annotations>
Index: test/org/openstreetmap/josm/tools/XmlObjectParserTest.java
===================================================================
--- test/org/openstreetmap/josm/tools/XmlObjectParserTest.java	(revision 193)
+++ test/org/openstreetmap/josm/tools/XmlObjectParserTest.java	(revision 193)
@@ -0,0 +1,131 @@
+package org.openstreetmap.josm.tools;
+
+import java.io.StringReader;
+import java.util.NoSuchElementException;
+
+import org.openstreetmap.josm.tools.XmlObjectParser.Uniform;
+
+import junit.framework.TestCase;
+
+public class XmlObjectParserTest extends TestCase {
+
+	private XmlObjectParser parser;
+
+	public static class Foo {
+		public String bar;
+	}
+	public static class Bar {
+		private String ada;
+		public void setAda(String value) {
+			ada = value;
+		}
+	}
+
+	@Override protected void setUp() throws Exception {
+		super.setUp();
+		parser = new XmlObjectParser();
+	}
+
+	private XmlObjectParser createParser(String string) {
+		XmlObjectParser parser = new XmlObjectParser();
+		parser.map("foo", Foo.class);
+		parser.start(new StringReader(string));
+		return parser;
+	}
+
+	public void testSimpleStructWithAttributes() throws Exception {
+		parser = createParser("<xml><foo bar='foobar'/><foo bar='baz'/></xml>");
+
+		assertEquals("foobar", ((Foo)parser.next()).bar);
+		assertEquals("baz", ((Foo)parser.next()).bar);
+		assertFalse(parser.hasNext());
+		try {
+			parser.next();
+			fail();
+		} catch (NoSuchElementException e) {
+		}
+	}
+
+	public void testSubtagsWithCharacters() throws Exception {
+		parser = createParser("<foo><bar>asd</bar></foo>");
+		assertEquals("asd", ((Foo)parser.next()).bar);
+	}
+
+	public void testManyTags() throws Exception {
+		StringBuilder b = new StringBuilder("<all>");
+		for (int i = 0; i < 50000; ++i) {
+			if (Math.random() > 0.5) {
+				b.append("<foo bar='blob");
+				b.append(i);
+				b.append("'/>");
+			} else {
+				b.append("<foo><bar>yuppel");
+				b.append(i);
+				b.append("</bar></foo>");
+			}
+		}
+		b.append("</all>");
+
+		System.gc();
+		long memBefore = Runtime.getRuntime().freeMemory();
+		parser = createParser(b.toString());
+		Thread.sleep(300);
+		System.gc();
+		long memAfter = Runtime.getRuntime().freeMemory();
+		assertTrue("2MB should be more than enough. "+(memAfter-memBefore), memAfter-memBefore < 2*1024*1024);
+
+		for (int i = 0; i < 50000; ++i) {
+			Foo f = (Foo)parser.next();
+			assertTrue(f.bar.equals("blob"+i) || f.bar.equals("yuppel"+i));
+		}
+		assertFalse(parser.hasNext());
+	}
+
+	public void testIterable() throws Exception {
+		parser = createParser("<xml><foo bar='yo'/><foo bar='yo'/><foo bar='yo'/></xml>");
+		for (Object o : parser)
+			assertEquals("yo", ((Foo)o).bar);
+	}
+
+	public void testUniformIterable() throws Exception {
+		XmlObjectParser.Uniform<Foo> p = new Uniform<Foo>(new StringReader("<xml><foo bar='sdf'/><foo bar='sdf'/></xml>"), "foo", Foo.class);
+		for (Foo foo : p)
+			assertEquals("sdf", foo.bar);
+	}
+
+
+	public void testObjectIntersection() throws Exception {
+		parser.map("foo", Foo.class);
+		parser.map("imi", Bar.class);
+		parser.start(new StringReader("<xml><foo bar='yo'><imi ada='123'/></foo></xml>"));
+
+		Object imi = parser.next();
+		Object foo = parser.next();
+		assertTrue(imi instanceof Bar);
+		assertTrue(foo instanceof Foo);
+		assertEquals("yo", ((Foo)foo).bar);
+		assertEquals("123", ((Bar)imi).ada);
+	}
+
+	public void testObjectIntersectionWithMapOnStart() throws Exception {
+		parser.mapOnStart("foo", Foo.class);
+		parser.map("imi", Bar.class);
+		parser.start(new StringReader("<xml><foo><imi/></foo></xml>"));
+
+		Object foo = parser.next();
+		Object imi = parser.next();
+		assertTrue(imi instanceof Bar);
+		assertTrue(foo instanceof Foo);
+	}
+
+	public void testMapReportsObjectsAndDoNotFillAttributes() throws Exception {
+		parser.map("foo", Foo.class);
+		parser.map("bar", Bar.class);
+		parser.start(new StringReader("<xml><foo><bar/></foo></xml>"));
+
+		assertTrue(parser.next() instanceof Bar);
+		Object foo = parser.next();
+		assertTrue(foo instanceof Foo);
+		assertNull(((Foo)foo).bar);
+	}
+}
