summaryrefslogtreecommitdiff
path: root/libcutl/tests/xml
diff options
context:
space:
mode:
Diffstat (limited to 'libcutl/tests/xml')
-rw-r--r--libcutl/tests/xml/makefile17
-rw-r--r--libcutl/tests/xml/parser/driver.cxx310
-rw-r--r--libcutl/tests/xml/parser/makefile69
-rw-r--r--libcutl/tests/xml/roundtrip/attribute.xml3
-rw-r--r--libcutl/tests/xml/roundtrip/characters.xml84
-rw-r--r--libcutl/tests/xml/roundtrip/driver.cxx127
-rw-r--r--libcutl/tests/xml/roundtrip/followup-1.xml8
-rw-r--r--libcutl/tests/xml/roundtrip/followup-2.xml1
-rw-r--r--libcutl/tests/xml/roundtrip/makefile74
-rw-r--r--libcutl/tests/xml/roundtrip/namespace.xml6
-rw-r--r--libcutl/tests/xml/serializer/driver.cxx63
-rw-r--r--libcutl/tests/xml/serializer/makefile69
12 files changed, 831 insertions, 0 deletions
diff --git a/libcutl/tests/xml/makefile b/libcutl/tests/xml/makefile
new file mode 100644
index 0000000..2073182
--- /dev/null
+++ b/libcutl/tests/xml/makefile
@@ -0,0 +1,17 @@
+# file : tests/xml/makefile
+# copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
+# license : MIT; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make
+
+tests := parser serializer roundtrip
+
+default := $(out_base)/
+test := $(out_base)/.test
+clean := $(out_base)/.clean
+
+$(default): $(addprefix $(out_base)/,$(addsuffix /,$(tests)))
+$(test): $(addprefix $(out_base)/,$(addsuffix /.test,$(tests)))
+$(clean): $(addprefix $(out_base)/,$(addsuffix /.clean,$(tests)))
+
+$(foreach t,$(tests),$(call import,$(src_base)/$t/makefile))
diff --git a/libcutl/tests/xml/parser/driver.cxx b/libcutl/tests/xml/parser/driver.cxx
new file mode 100644
index 0000000..39d5994
--- /dev/null
+++ b/libcutl/tests/xml/parser/driver.cxx
@@ -0,0 +1,310 @@
+// file : tests/xml/parser/driver.cxx
+// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#include <string>
+#include <cassert>
+#include <iostream>
+#include <sstream>
+
+#include <cutl/xml/parser.hxx>
+
+using namespace std;
+namespace xml = cutl::xml;
+using namespace xml;
+
+int
+main ()
+{
+ // Test error handling.
+ //
+ try
+ {
+ istringstream is ("<root><nested>X</nasted></root>");
+ parser p (is, "test");
+
+ assert (p.next () == parser::start_element);
+ assert (p.next () == parser::start_element);
+ assert (p.next () == parser::characters && p.value () == "X");
+ p.next ();
+ assert (false);
+ }
+ catch (const xml::exception& e)
+ {
+ // cerr << e.what () << endl;
+ }
+
+ try
+ {
+ istringstream is ("<root/>");
+ is.exceptions (ios_base::badbit | ios_base::failbit);
+ parser p (is, "test");
+
+ is.setstate (ios_base::badbit);
+ p.next ();
+ assert (false);
+ }
+ catch (const ios_base::failure& e)
+ {
+ }
+
+ // Test the next_expect() functionality.
+ //
+ {
+ istringstream is ("<root/>");
+ parser p (is, "test");
+ p.next_expect (parser::start_element, "root");
+ p.next_expect (parser::end_element);
+ }
+
+ try
+ {
+ istringstream is ("<root/>");
+ parser p (is, "test");
+ p.next_expect (parser::end_element);
+ assert (false);
+ }
+ catch (const xml::exception& e)
+ {
+ // cerr << e.what () << endl;
+ }
+
+ try
+ {
+ istringstream is ("<root/>");
+ parser p (is, "test");
+ p.next_expect (parser::start_element, "root1");
+ assert (false);
+ }
+ catch (const xml::exception& e)
+ {
+ // cerr << e.what () << endl;
+ }
+
+ // Test attribute maps.
+ //
+ {
+ istringstream is ("<root a='a' b='b' d='123' t='true'/>");
+ parser p (is, "test");
+ p.next_expect (parser::start_element, "root");
+
+ assert (p.attribute ("a") == "a");
+ assert (p.attribute ("b", "B") == "b");
+ assert (p.attribute ("c", "C") == "C");
+ assert (p.attribute<int> ("d") == 123);
+ assert (p.attribute<bool> ("t") == true);
+ assert (p.attribute ("f", false) == false);
+
+ p.next_expect (parser::end_element);
+ }
+
+ {
+ istringstream is ("<root a='a'><nested a='A'><inner/></nested></root>");
+ parser p (is, "test");
+ p.next_expect (parser::start_element, "root");
+ assert (p.attribute ("a") == "a");
+ assert (p.peek () == parser::start_element && p.name () == "nested");
+ assert (p.attribute ("a") == "a");
+ p.next_expect (parser::start_element, "nested");
+ assert (p.attribute ("a") == "A");
+ p.next_expect (parser::start_element, "inner");
+ assert (p.attribute ("a", "") == "");
+ p.next_expect (parser::end_element);
+ assert (p.attribute ("a") == "A");
+ assert (p.peek () == parser::end_element);
+ assert (p.attribute ("a") == "A"); // Still valid.
+ p.next_expect (parser::end_element);
+ assert (p.attribute ("a") == "a");
+ p.next_expect (parser::end_element);
+ assert (p.attribute ("a", "") == "");
+ }
+
+ try
+ {
+ istringstream is ("<root a='a' b='b'/>");
+ parser p (is, "test");
+ p.next_expect (parser::start_element, "root");
+ assert (p.attribute ("a") == "a");
+ p.next_expect (parser::end_element);
+ assert (false);
+ }
+ catch (const xml::exception& e)
+ {
+ // cerr << e.what () << endl;
+ }
+
+ try
+ {
+ istringstream is ("<root a='abc'/>");
+ parser p (is, "test");
+ p.next_expect (parser::start_element, "root");
+ p.attribute<int> ("a");
+ assert (false);
+ }
+ catch (const xml::exception& e)
+ {
+ // cerr << e.what () << endl;
+ }
+
+ // Test peeking and getting the current event.
+ //
+ {
+ istringstream is ("<root x='x'>x<nested/></root>");
+ parser p (is, "peek",
+ parser::receive_default | parser::receive_attributes_event);
+
+ assert (p.event () == parser::eof);
+
+ assert (p.peek () == parser::start_element);
+ assert (p.next () == parser::start_element);
+ assert (p.event () == parser::start_element);
+
+ assert (p.peek () == parser::start_attribute);
+ assert (p.event () == parser::start_attribute);
+ assert (p.next () == parser::start_attribute);
+
+ assert (p.peek () == parser::characters && p.value () == "x");
+ assert (p.next () == parser::characters && p.value () == "x");
+ assert (p.event () == parser::characters && p.value () == "x");
+
+ assert (p.peek () == parser::end_attribute);
+ assert (p.event () == parser::end_attribute);
+ assert (p.next () == parser::end_attribute);
+
+ assert (p.peek () == parser::characters && p.value () == "x");
+ assert (p.next () == parser::characters && p.value () == "x");
+ assert (p.event () == parser::characters && p.value () == "x");
+
+ assert (p.peek () == parser::start_element);
+ assert (p.next () == parser::start_element);
+ assert (p.event () == parser::start_element);
+
+ assert (p.peek () == parser::end_element);
+ assert (p.next () == parser::end_element);
+ assert (p.event () == parser::end_element);
+
+ assert (p.peek () == parser::end_element);
+ assert (p.next () == parser::end_element);
+ assert (p.event () == parser::end_element);
+
+ assert (p.peek () == parser::eof);
+ assert (p.next () == parser::eof);
+ assert (p.event () == parser::eof);
+ }
+
+ // Test content processing.
+ //
+
+ // empty
+ //
+ {
+ istringstream is ("<root x=' x '> \n\t </root>");
+ parser p (is, "empty",
+ parser::receive_default | parser::receive_attributes_event);
+
+ assert (p.next () == parser::start_element);
+ p.content (parser::empty);
+ assert (p.next () == parser::start_attribute);
+ assert (p.next () == parser::characters && p.value () == " x ");
+ assert (p.next () == parser::end_attribute);
+ assert (p.next () == parser::end_element);
+ assert (p.next () == parser::eof);
+ }
+
+ try
+ {
+ istringstream is ("<root> \n &amp; X \t </root>");
+ parser p (is, "empty");
+
+ assert (p.next () == parser::start_element);
+ p.content (parser::empty);
+ p.next ();
+ assert (false);
+ }
+ catch (const xml::exception& e)
+ {
+ // cerr << e.what () << endl;
+ }
+
+ // simple
+ //
+ {
+ istringstream is ("<root> X </root>");
+ parser p (is, "simple");
+
+ assert (p.next () == parser::start_element);
+ p.content (parser::simple);
+ assert (p.next () == parser::characters && p.value () == " X ");
+ assert (p.next () == parser::end_element);
+ assert (p.next () == parser::eof);
+ }
+
+ try
+ {
+ istringstream is ("<root> ? <nested/></root>");
+ parser p (is, "simple");
+
+ assert (p.next () == parser::start_element);
+ p.content (parser::simple);
+ assert (p.next () == parser::characters && p.value () == " ? ");
+ p.next ();
+ assert (false);
+ }
+ catch (const xml::exception& e)
+ {
+ // cerr << e.what () << endl;
+ }
+
+ // complex
+ //
+ {
+ istringstream is ("<root x=' x '>\n"
+ " <nested>\n"
+ " <inner/>\n"
+ " <inner> X </inner>\n"
+ " </nested>\n"
+ "</root>\n");
+ parser p (is, "complex",
+ parser::receive_default | parser::receive_attributes_event);
+
+ assert (p.next () == parser::start_element); // root
+ p.content (parser::complex);
+
+ assert (p.next () == parser::start_attribute);
+ assert (p.next () == parser::characters && p.value () == " x ");
+ assert (p.next () == parser::end_attribute);
+
+ assert (p.next () == parser::start_element); // nested
+ p.content (parser::complex);
+
+ assert (p.next () == parser::start_element); // inner
+ p.content (parser::empty);
+ assert (p.next () == parser::end_element); // inner
+
+ assert (p.next () == parser::start_element); // inner
+ p.content (parser::simple);
+ assert (p.next () == parser::characters && p.value () == " X ");
+ assert (p.next () == parser::end_element); // inner
+
+ assert (p.next () == parser::end_element); // nested
+ assert (p.next () == parser::end_element); // root
+ assert (p.next () == parser::eof);
+ }
+
+ try
+ {
+ istringstream is ("<root> \n<n/> X <n> X </n> </root>");
+ parser p (is, "complex");
+
+ assert (p.next () == parser::start_element);
+ p.content (parser::complex);
+ assert (p.next () == parser::start_element);
+ assert (p.next () == parser::end_element);
+ p.next ();
+ assert (false);
+ }
+ catch (const xml::exception& e)
+ {
+ // cerr << e.what () << endl;
+ }
+}
diff --git a/libcutl/tests/xml/parser/makefile b/libcutl/tests/xml/parser/makefile
new file mode 100644
index 0000000..f654976
--- /dev/null
+++ b/libcutl/tests/xml/parser/makefile
@@ -0,0 +1,69 @@
+# file : tests/xml/parser/makefile
+# copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
+# license : MIT; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make
+
+cxx_tun := driver.cxx
+
+#
+#
+cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o))
+cxx_od := $(cxx_obj:.o=.o.d)
+
+cutl.l := $(out_root)/cutl/cutl.l
+cutl.l.cpp-options := $(out_root)/cutl/cutl.l.cpp-options
+
+driver := $(out_base)/driver
+test := $(out_base)/.test
+clean := $(out_base)/.clean
+
+# Build.
+#
+$(driver): $(cxx_obj) $(cutl.l)
+$(cxx_obj) $(cxx_od): $(cutl.l.cpp-options)
+
+
+$(call include-dep,$(cxx_od))
+
+
+# Alias for default target.
+#
+$(out_base)/: $(driver)
+
+
+# Test.
+#
+$(test): $(driver)
+ $(call message,test $<,$<)
+
+
+# Clean.
+#
+$(clean): \
+ $(driver).o.clean \
+ $(addsuffix .cxx.clean,$(cxx_obj)) \
+ $(addsuffix .cxx.clean,$(cxx_od))
+
+
+# Generated .gitignore.
+#
+ifeq ($(out_base),$(src_base))
+$(driver): | $(out_base)/.gitignore
+
+$(out_base)/.gitignore: files := driver
+$(clean): $(out_base)/.gitignore.clean
+
+$(call include,$(bld_root)/git/gitignore.make)
+endif
+
+
+# How to.
+#
+$(call include,$(bld_root)/cxx/o-e.make)
+$(call include,$(bld_root)/cxx/cxx-o.make)
+$(call include,$(bld_root)/cxx/cxx-d.make)
+
+# Dependencies.
+#
+$(call import,$(src_root)/cutl/makefile)
diff --git a/libcutl/tests/xml/roundtrip/attribute.xml b/libcutl/tests/xml/roundtrip/attribute.xml
new file mode 100644
index 0000000..ca32460
--- /dev/null
+++ b/libcutl/tests/xml/roundtrip/attribute.xml
@@ -0,0 +1,3 @@
+<root xmlns="foo" xmlns:b="bar" x="x" b:y="y">
+ <nested b:x="x" y="y"/>
+</root>
diff --git a/libcutl/tests/xml/roundtrip/characters.xml b/libcutl/tests/xml/roundtrip/characters.xml
new file mode 100644
index 0000000..fab909b
--- /dev/null
+++ b/libcutl/tests/xml/roundtrip/characters.xml
@@ -0,0 +1,84 @@
+<root x="aaaaaaaa&quot;bbbbbbbbbb">
+ <nested>
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ </nested>
+</root>
diff --git a/libcutl/tests/xml/roundtrip/driver.cxx b/libcutl/tests/xml/roundtrip/driver.cxx
new file mode 100644
index 0000000..b0b6497
--- /dev/null
+++ b/libcutl/tests/xml/roundtrip/driver.cxx
@@ -0,0 +1,127 @@
+// file : tests/xml/roundtrip/driver.cxx
+// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#include <string>
+#include <fstream>
+#include <cassert>
+#include <iostream>
+
+#include <cutl/xml/parser.hxx>
+#include <cutl/xml/serializer.hxx>
+
+using namespace std;
+namespace xml = cutl::xml;
+using namespace xml;
+
+const bool trace = false;
+
+int
+main (int argc, char* argv[])
+{
+ if (argc != 2)
+ {
+ cerr << "usage: " << argv[0] << " <xml-file>" << endl;
+ return 1;
+ }
+
+ try
+ {
+ ifstream ifs;
+ ifs.exceptions (ifstream::badbit | ifstream::failbit);
+ ifs.open (argv[1], ifstream::in | ifstream::binary);
+
+ parser p (ifs,
+ argv[1],
+ parser::receive_default |
+ parser::receive_attributes_event |
+ parser::receive_namespace_decls);
+
+ serializer s (cout, "out", 0);
+
+ bool in_attr (false);
+ for (parser::event_type e (p.next ()); e != parser::eof; e = p.next ())
+ {
+ switch (e)
+ {
+ case parser::start_element:
+ {
+ if (trace)
+ cerr << p.line () << ':' << p.column () << ": " << e << " "
+ << p.namespace_() << (p.namespace_().empty () ? "" : "#")
+ << p.prefix () << (p.prefix ().empty () ? "" : ":")
+ << p.name () << endl;
+
+ s.start_element (p.qname ());
+ break;
+ }
+ case parser::end_element:
+ {
+ if (trace)
+ cerr << p.line () << ':' << p.column () << ": " << e << " "
+ << p.namespace_() << (p.namespace_().empty () ? "" : "#")
+ << p.prefix () << (p.prefix ().empty () ? "" : ":")
+ << p.name () << endl;
+
+ s.end_element ();
+ break;
+ }
+ case parser::start_namespace_decl:
+ {
+ if (trace)
+ cerr << " " << p.prefix () << "->" << p.namespace_ () << endl;
+
+ s.namespace_decl (p.namespace_ (), p.prefix ());
+ break;
+ }
+ case parser::end_namespace_decl:
+ {
+ if (trace)
+ cerr << " " << p.prefix () << "-x" << endl;
+
+ break;
+ }
+ case parser::start_attribute:
+ {
+ if (trace)
+ cerr << " " << p.qname () << "=";
+
+ s.start_attribute (p.qname ());
+ in_attr = true;
+ break;
+ }
+ case parser::end_attribute:
+ {
+ s.end_attribute ();
+ in_attr = false;
+ break;
+ }
+ case parser::characters:
+ {
+ if (trace)
+ {
+ if (!in_attr)
+ cerr << p.line () << ':' << p.column () << ": " << e << " ";
+
+ cerr << "'" << p.value () << "'" << endl;
+ }
+
+ s.characters (p.value ());
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ catch (const ios_base::failure& e)
+ {
+ cerr << "io failure" << endl;
+ return 1;
+ }
+ catch (const xml::exception& e)
+ {
+ cerr << e.what () << endl;
+ return 1;
+ }
+}
diff --git a/libcutl/tests/xml/roundtrip/followup-1.xml b/libcutl/tests/xml/roundtrip/followup-1.xml
new file mode 100644
index 0000000..c2a3b22
--- /dev/null
+++ b/libcutl/tests/xml/roundtrip/followup-1.xml
@@ -0,0 +1,8 @@
+<root xmlns="foo" xmlns:b="bar">
+ <nested xmlns:c="cox">
+ <c:inner>x</c:inner>
+ </nested>
+ <empty/>
+ <empty x="x"/>
+ <split>foo&amp;bar</split>
+</root>
diff --git a/libcutl/tests/xml/roundtrip/followup-2.xml b/libcutl/tests/xml/roundtrip/followup-2.xml
new file mode 100644
index 0000000..70171eb
--- /dev/null
+++ b/libcutl/tests/xml/roundtrip/followup-2.xml
@@ -0,0 +1 @@
+<empty x="x"/>
diff --git a/libcutl/tests/xml/roundtrip/makefile b/libcutl/tests/xml/roundtrip/makefile
new file mode 100644
index 0000000..9769593
--- /dev/null
+++ b/libcutl/tests/xml/roundtrip/makefile
@@ -0,0 +1,74 @@
+# file : tests/xml/roundtrip/makefile
+# copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
+# license : MIT; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make
+
+cxx_tun := driver.cxx
+
+#
+#
+cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o))
+cxx_od := $(cxx_obj:.o=.o.d)
+
+cutl.l := $(out_root)/cutl/cutl.l
+cutl.l.cpp-options := $(out_root)/cutl/cutl.l.cpp-options
+
+driver := $(out_base)/driver
+test := $(out_base)/.test
+clean := $(out_base)/.clean
+
+# Build.
+#
+$(driver): $(cxx_obj) $(cutl.l)
+$(cxx_obj) $(cxx_od): $(cutl.l.cpp-options)
+
+
+$(call include-dep,$(cxx_od))
+
+
+# Alias for default target.
+#
+$(out_base)/: $(driver)
+
+
+# Test.
+#
+$(test): tests := attribute.xml namespace.xml followup-1.xml followup-2.xml \
+characters.xml
+
+$(test): test_body = $(call message,test $< $1,$< $(src_base)/$1 >$(out_base)/test.out)$(literal_newline)\
+$(literal_tab)$(call message,,diff -u $(src_base)/$1 $(out_base)/test.out)$(literal_newline)\
+$(literal_tab)$(call message,,rm -f $(out_base)/test.out)$(literal_newline)
+$(test): $(driver)
+ $(foreach t,$(tests),$(call test_body,$t))
+
+# Clean.
+#
+$(clean): \
+ $(driver).o.clean \
+ $(addsuffix .cxx.clean,$(cxx_obj)) \
+ $(addsuffix .cxx.clean,$(cxx_od))
+
+
+# Generated .gitignore.
+#
+ifeq ($(out_base),$(src_base))
+$(driver): | $(out_base)/.gitignore
+
+$(out_base)/.gitignore: files := driver
+$(clean): $(out_base)/.gitignore.clean
+
+$(call include,$(bld_root)/git/gitignore.make)
+endif
+
+
+# How to.
+#
+$(call include,$(bld_root)/cxx/o-e.make)
+$(call include,$(bld_root)/cxx/cxx-o.make)
+$(call include,$(bld_root)/cxx/cxx-d.make)
+
+# Dependencies.
+#
+$(call import,$(src_root)/cutl/makefile)
diff --git a/libcutl/tests/xml/roundtrip/namespace.xml b/libcutl/tests/xml/roundtrip/namespace.xml
new file mode 100644
index 0000000..4a5642e
--- /dev/null
+++ b/libcutl/tests/xml/roundtrip/namespace.xml
@@ -0,0 +1,6 @@
+<root xmlns="foo" xmlns:b="bar" b:a="a">
+ <nested>
+ <inner xmlns="">X</inner>
+ </nested>
+ <f:nested xmlns:f="fox"/>
+</root>
diff --git a/libcutl/tests/xml/serializer/driver.cxx b/libcutl/tests/xml/serializer/driver.cxx
new file mode 100644
index 0000000..869bb8e
--- /dev/null
+++ b/libcutl/tests/xml/serializer/driver.cxx
@@ -0,0 +1,63 @@
+// file : tests/xml/serializer/driver.cxx
+// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#include <string>
+#include <cassert>
+#include <iostream>
+#include <sstream>
+
+#include <cutl/xml/serializer.hxx>
+
+using namespace std;
+namespace xml = cutl::xml;
+using namespace xml;
+
+int
+main ()
+{
+ // Test error handling.
+ //
+ try
+ {
+ ostringstream os;
+ serializer s (os, "test");
+
+ s.attribute ("foo", "bar");
+ assert (false);
+ }
+ catch (const xml::exception& e)
+ {
+ // cerr << e.what () << endl;
+ }
+
+ try
+ {
+ ostringstream os;
+ os.exceptions (ios_base::badbit | ios_base::failbit);
+ serializer s (os, "test");
+
+ s.start_element ("root");
+ s.characters ("one");
+ os.setstate (ios_base::badbit);
+ s.characters ("two");
+ assert (false);
+ }
+ catch (const ios_base::failure& e)
+ {
+ }
+
+ // Test value serialization.
+ //
+ {
+ ostringstream os;
+ serializer s (os, "test", 0);
+
+ s.start_element ("root");
+ s.attribute ("version", 123);
+ s.characters (true);
+ s.end_element ();
+
+ assert (os.str () == "<root version=\"123\">true</root>\n");
+ }
+}
diff --git a/libcutl/tests/xml/serializer/makefile b/libcutl/tests/xml/serializer/makefile
new file mode 100644
index 0000000..8bd1a4a
--- /dev/null
+++ b/libcutl/tests/xml/serializer/makefile
@@ -0,0 +1,69 @@
+# file : tests/xml/serializer/makefile
+# copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
+# license : MIT; see accompanying LICENSE file
+
+include $(dir $(lastword $(MAKEFILE_LIST)))../../../build/bootstrap.make
+
+cxx_tun := driver.cxx
+
+#
+#
+cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o))
+cxx_od := $(cxx_obj:.o=.o.d)
+
+cutl.l := $(out_root)/cutl/cutl.l
+cutl.l.cpp-options := $(out_root)/cutl/cutl.l.cpp-options
+
+driver := $(out_base)/driver
+test := $(out_base)/.test
+clean := $(out_base)/.clean
+
+# Build.
+#
+$(driver): $(cxx_obj) $(cutl.l)
+$(cxx_obj) $(cxx_od): $(cutl.l.cpp-options)
+
+
+$(call include-dep,$(cxx_od))
+
+
+# Alias for default target.
+#
+$(out_base)/: $(driver)
+
+
+# Test.
+#
+$(test): $(driver)
+ $(call message,test $<,$<)
+
+
+# Clean.
+#
+$(clean): \
+ $(driver).o.clean \
+ $(addsuffix .cxx.clean,$(cxx_obj)) \
+ $(addsuffix .cxx.clean,$(cxx_od))
+
+
+# Generated .gitignore.
+#
+ifeq ($(out_base),$(src_base))
+$(driver): | $(out_base)/.gitignore
+
+$(out_base)/.gitignore: files := driver
+$(clean): $(out_base)/.gitignore.clean
+
+$(call include,$(bld_root)/git/gitignore.make)
+endif
+
+
+# How to.
+#
+$(call include,$(bld_root)/cxx/o-e.make)
+$(call include,$(bld_root)/cxx/cxx-o.make)
+$(call include,$(bld_root)/cxx/cxx-d.make)
+
+# Dependencies.
+#
+$(call import,$(src_root)/cutl/makefile)