mirror of
https://forge.sourceware.org/marek/gcc.git
synced 2026-02-22 03:47:02 -05:00
diagnostics: move xml defs to a new xml.cc
While prototyping new features I'm finding it helpful to use XML beyond the "experimental-html" diagnostics sink. Move the implementation of the xml classes to their own file. No functional change intended. gcc/ChangeLog: * Makefile.in (OBJS-libcommon): Add xml.o. * diagnostic-format-html.cc (namespace xml): Move implementation to xml.cc (selftest::test_printer): Likewise. (selftest::test_attribute_ordering): Likewise. (selftest::diagnostic_format_html_cc_tests): Don't call the moved tests here; they will be called from xml_cc_tests in xml.cc. * selftest-run-tests.cc (selftest::run_tests): Call xml_cc_tests. * selftest.h (selftest::xml_cc_tests): New decl. * xml.cc: New file, based on material from diagnostic-format-html.cc. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
@@ -1862,6 +1862,7 @@ OBJS-libcommon = diagnostic-spec.o diagnostic.o diagnostic-color.o \
|
||||
edit-context.o \
|
||||
pretty-print.o intl.o \
|
||||
json.o json-parsing.o \
|
||||
xml.o \
|
||||
sbitmap.o \
|
||||
vec.o input.o hash-table.o ggc-none.o memory-block.o \
|
||||
selftest.o selftest-diagnostic.o sort.o \
|
||||
|
||||
@@ -49,256 +49,6 @@ html_generation_options::html_generation_options ()
|
||||
{
|
||||
}
|
||||
|
||||
namespace xml {
|
||||
|
||||
/* Disable warnings about quoting issues in the pp_xxx calls below
|
||||
that (intentionally) don't follow GCC diagnostic conventions. */
|
||||
#if __GNUC__ >= 10
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wformat-diag"
|
||||
#endif
|
||||
|
||||
|
||||
/* Implementation. */
|
||||
|
||||
static void
|
||||
write_escaped_text (pretty_printer *pp, const char *text)
|
||||
{
|
||||
gcc_assert (text);
|
||||
|
||||
for (const char *p = text; *p; ++p)
|
||||
{
|
||||
char ch = *p;
|
||||
switch (ch)
|
||||
{
|
||||
default:
|
||||
pp_character (pp, ch);
|
||||
break;
|
||||
case '\'':
|
||||
pp_string (pp, "'");
|
||||
break;
|
||||
case '"':
|
||||
pp_string (pp, """);
|
||||
break;
|
||||
case '&':
|
||||
pp_string (pp, "&");
|
||||
break;
|
||||
case '<':
|
||||
pp_string (pp, "<");
|
||||
break;
|
||||
case '>':
|
||||
pp_string (pp, ">");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* struct node. */
|
||||
|
||||
void
|
||||
node::dump (FILE *out) const
|
||||
{
|
||||
pretty_printer pp;
|
||||
pp.set_output_stream (out);
|
||||
write_as_xml (&pp, 0, true);
|
||||
pp_flush (&pp);
|
||||
}
|
||||
|
||||
/* struct text : public node. */
|
||||
|
||||
void
|
||||
text::write_as_xml (pretty_printer *pp, int depth, bool indent) const
|
||||
{
|
||||
if (indent)
|
||||
{
|
||||
for (int i = 0; i < depth; ++i)
|
||||
pp_string (pp, " ");
|
||||
}
|
||||
write_escaped_text (pp, m_str.c_str ());
|
||||
if (indent)
|
||||
pp_newline (pp);
|
||||
}
|
||||
|
||||
/* struct node_with_children : public node. */
|
||||
|
||||
void
|
||||
node_with_children::add_child (std::unique_ptr<node> node)
|
||||
{
|
||||
gcc_assert (node.get ());
|
||||
m_children.push_back (std::move (node));
|
||||
}
|
||||
|
||||
void
|
||||
node_with_children::add_text (std::string str)
|
||||
{
|
||||
// Consolidate runs of text
|
||||
if (!m_children.empty ())
|
||||
if (text *t = m_children.back ()->dyn_cast_text ())
|
||||
{
|
||||
t->m_str += std::move (str);
|
||||
return;
|
||||
}
|
||||
add_child (std::make_unique <text> (std::move (str)));
|
||||
}
|
||||
|
||||
|
||||
/* struct document : public node_with_children. */
|
||||
|
||||
void
|
||||
document::write_as_xml (pretty_printer *pp, int depth, bool indent) const
|
||||
{
|
||||
pp_string (pp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
pp_string (pp, "<!DOCTYPE html\n"
|
||||
" PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n"
|
||||
" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
|
||||
if (indent)
|
||||
pp_newline (pp);
|
||||
for (auto &iter : m_children)
|
||||
iter->write_as_xml (pp, depth, indent);
|
||||
}
|
||||
|
||||
/* struct element : public node_with_children. */
|
||||
|
||||
void
|
||||
element::write_as_xml (pretty_printer *pp, int depth, bool indent) const
|
||||
{
|
||||
if (indent)
|
||||
{
|
||||
for (int i = 0; i < depth; ++i)
|
||||
pp_string (pp, " ");
|
||||
}
|
||||
|
||||
pp_printf (pp, "<%s", m_kind.c_str ());
|
||||
for (auto &key : m_key_insertion_order)
|
||||
{
|
||||
auto iter = m_attributes.find (key);
|
||||
if (iter != m_attributes.end ())
|
||||
{
|
||||
pp_printf (pp, " %s=\"", key.c_str ());
|
||||
write_escaped_text (pp, iter->second.c_str ());
|
||||
pp_string (pp, "\"");
|
||||
}
|
||||
}
|
||||
if (m_children.empty ())
|
||||
pp_string (pp, "/>");
|
||||
else
|
||||
{
|
||||
const bool indent_children = m_preserve_whitespace ? false : indent;
|
||||
pp_string (pp, ">");
|
||||
if (indent_children)
|
||||
pp_newline (pp);
|
||||
for (auto &child : m_children)
|
||||
child->write_as_xml (pp, depth + 1, indent_children);
|
||||
if (indent_children)
|
||||
{
|
||||
for (int i = 0; i < depth; ++i)
|
||||
pp_string (pp, " ");
|
||||
}
|
||||
pp_printf (pp, "</%s>", m_kind.c_str ());
|
||||
}
|
||||
|
||||
if (indent)
|
||||
pp_newline (pp);
|
||||
}
|
||||
|
||||
void
|
||||
element::set_attr (const char *name, std::string value)
|
||||
{
|
||||
auto iter = m_attributes.find (name);
|
||||
if (iter == m_attributes.end ())
|
||||
m_key_insertion_order.push_back (name);
|
||||
m_attributes[name] = std::move (value);
|
||||
}
|
||||
|
||||
// struct raw : public node
|
||||
|
||||
void
|
||||
raw::write_as_xml (pretty_printer *pp,
|
||||
int /*depth*/, bool /*indent*/) const
|
||||
{
|
||||
pp_string (pp, m_xml_src.c_str ());
|
||||
}
|
||||
|
||||
#if __GNUC__ >= 10
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
// class printer
|
||||
|
||||
printer::printer (element &insertion_point)
|
||||
{
|
||||
m_open_tags.push_back (&insertion_point);
|
||||
}
|
||||
|
||||
void
|
||||
printer::push_tag (std::string name,
|
||||
bool preserve_whitespace)
|
||||
{
|
||||
push_element
|
||||
(std::make_unique<element> (std::move (name),
|
||||
preserve_whitespace));
|
||||
}
|
||||
|
||||
void
|
||||
printer::push_tag_with_class (std::string name, std::string class_,
|
||||
bool preserve_whitespace)
|
||||
{
|
||||
auto new_element
|
||||
= std::make_unique<element> (std::move (name),
|
||||
preserve_whitespace);
|
||||
new_element->set_attr ("class", class_);
|
||||
push_element (std::move (new_element));
|
||||
}
|
||||
|
||||
void
|
||||
printer::pop_tag ()
|
||||
{
|
||||
m_open_tags.pop_back ();
|
||||
}
|
||||
|
||||
void
|
||||
printer::set_attr (const char *name, std::string value)
|
||||
{
|
||||
m_open_tags.back ()->set_attr (name, value);
|
||||
}
|
||||
|
||||
void
|
||||
printer::add_text (std::string text)
|
||||
{
|
||||
element *parent = m_open_tags.back ();
|
||||
parent->add_text (std::move (text));
|
||||
}
|
||||
|
||||
void
|
||||
printer::add_raw (std::string text)
|
||||
{
|
||||
element *parent = m_open_tags.back ();
|
||||
parent->add_child (std::make_unique<xml::raw> (std::move (text)));
|
||||
}
|
||||
|
||||
void
|
||||
printer::push_element (std::unique_ptr<element> new_element)
|
||||
{
|
||||
element *parent = m_open_tags.back ();
|
||||
m_open_tags.push_back (new_element.get ());
|
||||
parent->add_child (std::move (new_element));
|
||||
}
|
||||
|
||||
void
|
||||
printer::append (std::unique_ptr<node> new_node)
|
||||
{
|
||||
element *parent = m_open_tags.back ();
|
||||
parent->add_child (std::move (new_node));
|
||||
}
|
||||
|
||||
element *
|
||||
printer::get_insertion_point () const
|
||||
{
|
||||
return m_open_tags.back ();
|
||||
}
|
||||
|
||||
} // namespace xml
|
||||
|
||||
class html_builder;
|
||||
|
||||
/* Concrete buffering implementation subclass for HTML output. */
|
||||
@@ -1288,67 +1038,6 @@ test_metadata ()
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_printer ()
|
||||
{
|
||||
xml::element top ("top", false);
|
||||
xml::printer xp (top);
|
||||
xp.push_tag ("foo");
|
||||
xp.add_text ("hello");
|
||||
xp.push_tag ("bar");
|
||||
xp.set_attr ("size", "3");
|
||||
xp.set_attr ("color", "red");
|
||||
xp.add_text ("world");
|
||||
xp.push_tag ("baz");
|
||||
xp.pop_tag ();
|
||||
xp.pop_tag ();
|
||||
xp.pop_tag ();
|
||||
|
||||
pretty_printer pp;
|
||||
top.write_as_xml (&pp, 0, true);
|
||||
ASSERT_STREQ
|
||||
(pp_formatted_text (&pp),
|
||||
"<top>\n"
|
||||
" <foo>\n"
|
||||
" hello\n"
|
||||
" <bar size=\"3\" color=\"red\">\n"
|
||||
" world\n"
|
||||
" <baz/>\n"
|
||||
" </bar>\n"
|
||||
" </foo>\n"
|
||||
"</top>\n");
|
||||
}
|
||||
|
||||
// Verify that element attributes preserve insertion order.
|
||||
|
||||
static void
|
||||
test_attribute_ordering ()
|
||||
{
|
||||
xml::element top ("top", false);
|
||||
xml::printer xp (top);
|
||||
xp.push_tag ("chronological");
|
||||
xp.set_attr ("maldon", "991");
|
||||
xp.set_attr ("hastings", "1066");
|
||||
xp.set_attr ("edgehill", "1642");
|
||||
xp.set_attr ("naseby", "1645");
|
||||
xp.pop_tag ();
|
||||
xp.push_tag ("alphabetical");
|
||||
xp.set_attr ("edgehill", "1642");
|
||||
xp.set_attr ("hastings", "1066");
|
||||
xp.set_attr ("maldon", "991");
|
||||
xp.set_attr ("naseby", "1645");
|
||||
xp.pop_tag ();
|
||||
|
||||
pretty_printer pp;
|
||||
top.write_as_xml (&pp, 0, true);
|
||||
ASSERT_STREQ
|
||||
(pp_formatted_text (&pp),
|
||||
"<top>\n"
|
||||
" <chronological maldon=\"991\" hastings=\"1066\" edgehill=\"1642\" naseby=\"1645\"/>\n"
|
||||
" <alphabetical edgehill=\"1642\" hastings=\"1066\" maldon=\"991\" naseby=\"1645\"/>\n"
|
||||
"</top>\n");
|
||||
}
|
||||
|
||||
/* Run all of the selftests within this file. */
|
||||
|
||||
void
|
||||
@@ -1357,8 +1046,6 @@ diagnostic_format_html_cc_tests ()
|
||||
auto_fix_quotes fix_quotes;
|
||||
test_simple_log ();
|
||||
test_metadata ();
|
||||
test_printer ();
|
||||
test_attribute_ordering ();
|
||||
}
|
||||
|
||||
} // namespace selftest
|
||||
|
||||
@@ -80,6 +80,7 @@ selftest::run_tests ()
|
||||
optinfo_emit_json_cc_tests ();
|
||||
ordered_hash_map_tests_cc_tests ();
|
||||
splay_tree_cc_tests ();
|
||||
xml_cc_tests ();
|
||||
|
||||
/* Mid-level data structures. */
|
||||
input_cc_tests ();
|
||||
|
||||
@@ -276,6 +276,7 @@ extern void typed_splay_tree_cc_tests ();
|
||||
extern void vec_cc_tests ();
|
||||
extern void vec_perm_indices_cc_tests ();
|
||||
extern void wide_int_cc_tests ();
|
||||
extern void xml_cc_tests ();
|
||||
|
||||
extern int num_passes;
|
||||
|
||||
|
||||
358
gcc/xml.cc
Normal file
358
gcc/xml.cc
Normal file
@@ -0,0 +1,358 @@
|
||||
/* XML support for diagnostics.
|
||||
Copyright (C) 2024-2025 Free Software Foundation, Inc.
|
||||
Contributed by David Malcolm <dmalcolm@redhat.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 3, or (at your option) any later
|
||||
version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
#define INCLUDE_MAP
|
||||
#define INCLUDE_STRING
|
||||
#define INCLUDE_VECTOR
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "xml.h"
|
||||
#include "xml-printer.h"
|
||||
#include "pretty-print.h"
|
||||
#include "selftest.h"
|
||||
|
||||
namespace xml {
|
||||
|
||||
/* Disable warnings about quoting issues in the pp_xxx calls below
|
||||
that (intentionally) don't follow GCC diagnostic conventions. */
|
||||
#if __GNUC__ >= 10
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wformat-diag"
|
||||
#endif
|
||||
|
||||
|
||||
/* Implementation. */
|
||||
|
||||
static void
|
||||
write_escaped_text (pretty_printer *pp, const char *text)
|
||||
{
|
||||
gcc_assert (text);
|
||||
|
||||
for (const char *p = text; *p; ++p)
|
||||
{
|
||||
char ch = *p;
|
||||
switch (ch)
|
||||
{
|
||||
default:
|
||||
pp_character (pp, ch);
|
||||
break;
|
||||
case '\'':
|
||||
pp_string (pp, "'");
|
||||
break;
|
||||
case '"':
|
||||
pp_string (pp, """);
|
||||
break;
|
||||
case '&':
|
||||
pp_string (pp, "&");
|
||||
break;
|
||||
case '<':
|
||||
pp_string (pp, "<");
|
||||
break;
|
||||
case '>':
|
||||
pp_string (pp, ">");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* struct node. */
|
||||
|
||||
void
|
||||
node::dump (FILE *out) const
|
||||
{
|
||||
pretty_printer pp;
|
||||
pp.set_output_stream (out);
|
||||
write_as_xml (&pp, 0, true);
|
||||
pp_flush (&pp);
|
||||
}
|
||||
|
||||
/* struct text : public node. */
|
||||
|
||||
void
|
||||
text::write_as_xml (pretty_printer *pp, int depth, bool indent) const
|
||||
{
|
||||
if (indent)
|
||||
{
|
||||
for (int i = 0; i < depth; ++i)
|
||||
pp_string (pp, " ");
|
||||
}
|
||||
write_escaped_text (pp, m_str.c_str ());
|
||||
if (indent)
|
||||
pp_newline (pp);
|
||||
}
|
||||
|
||||
/* struct node_with_children : public node. */
|
||||
|
||||
void
|
||||
node_with_children::add_child (std::unique_ptr<node> node)
|
||||
{
|
||||
gcc_assert (node.get ());
|
||||
m_children.push_back (std::move (node));
|
||||
}
|
||||
|
||||
void
|
||||
node_with_children::add_text (std::string str)
|
||||
{
|
||||
// Consolidate runs of text
|
||||
if (!m_children.empty ())
|
||||
if (text *t = m_children.back ()->dyn_cast_text ())
|
||||
{
|
||||
t->m_str += std::move (str);
|
||||
return;
|
||||
}
|
||||
add_child (std::make_unique <text> (std::move (str)));
|
||||
}
|
||||
|
||||
|
||||
/* struct document : public node_with_children. */
|
||||
|
||||
void
|
||||
document::write_as_xml (pretty_printer *pp, int depth, bool indent) const
|
||||
{
|
||||
pp_string (pp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
pp_string (pp, "<!DOCTYPE html\n"
|
||||
" PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n"
|
||||
" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
|
||||
if (indent)
|
||||
pp_newline (pp);
|
||||
for (auto &iter : m_children)
|
||||
iter->write_as_xml (pp, depth, indent);
|
||||
}
|
||||
|
||||
/* struct element : public node_with_children. */
|
||||
|
||||
void
|
||||
element::write_as_xml (pretty_printer *pp, int depth, bool indent) const
|
||||
{
|
||||
if (indent)
|
||||
{
|
||||
for (int i = 0; i < depth; ++i)
|
||||
pp_string (pp, " ");
|
||||
}
|
||||
|
||||
pp_printf (pp, "<%s", m_kind.c_str ());
|
||||
for (auto &key : m_key_insertion_order)
|
||||
{
|
||||
auto iter = m_attributes.find (key);
|
||||
if (iter != m_attributes.end ())
|
||||
{
|
||||
pp_printf (pp, " %s=\"", key.c_str ());
|
||||
write_escaped_text (pp, iter->second.c_str ());
|
||||
pp_string (pp, "\"");
|
||||
}
|
||||
}
|
||||
if (m_children.empty ())
|
||||
pp_string (pp, "/>");
|
||||
else
|
||||
{
|
||||
const bool indent_children = m_preserve_whitespace ? false : indent;
|
||||
pp_string (pp, ">");
|
||||
if (indent_children)
|
||||
pp_newline (pp);
|
||||
for (auto &child : m_children)
|
||||
child->write_as_xml (pp, depth + 1, indent_children);
|
||||
if (indent_children)
|
||||
{
|
||||
for (int i = 0; i < depth; ++i)
|
||||
pp_string (pp, " ");
|
||||
}
|
||||
pp_printf (pp, "</%s>", m_kind.c_str ());
|
||||
}
|
||||
|
||||
if (indent)
|
||||
pp_newline (pp);
|
||||
}
|
||||
|
||||
void
|
||||
element::set_attr (const char *name, std::string value)
|
||||
{
|
||||
auto iter = m_attributes.find (name);
|
||||
if (iter == m_attributes.end ())
|
||||
m_key_insertion_order.push_back (name);
|
||||
m_attributes[name] = std::move (value);
|
||||
}
|
||||
|
||||
// struct raw : public node
|
||||
|
||||
void
|
||||
raw::write_as_xml (pretty_printer *pp,
|
||||
int /*depth*/, bool /*indent*/) const
|
||||
{
|
||||
pp_string (pp, m_xml_src.c_str ());
|
||||
}
|
||||
|
||||
#if __GNUC__ >= 10
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
// class printer
|
||||
|
||||
printer::printer (element &insertion_point)
|
||||
{
|
||||
m_open_tags.push_back (&insertion_point);
|
||||
}
|
||||
|
||||
void
|
||||
printer::push_tag (std::string name,
|
||||
bool preserve_whitespace)
|
||||
{
|
||||
push_element
|
||||
(std::make_unique<element> (std::move (name),
|
||||
preserve_whitespace));
|
||||
}
|
||||
|
||||
void
|
||||
printer::push_tag_with_class (std::string name, std::string class_,
|
||||
bool preserve_whitespace)
|
||||
{
|
||||
auto new_element
|
||||
= std::make_unique<element> (std::move (name),
|
||||
preserve_whitespace);
|
||||
new_element->set_attr ("class", class_);
|
||||
push_element (std::move (new_element));
|
||||
}
|
||||
|
||||
void
|
||||
printer::pop_tag ()
|
||||
{
|
||||
m_open_tags.pop_back ();
|
||||
}
|
||||
|
||||
void
|
||||
printer::set_attr (const char *name, std::string value)
|
||||
{
|
||||
m_open_tags.back ()->set_attr (name, value);
|
||||
}
|
||||
|
||||
void
|
||||
printer::add_text (std::string text)
|
||||
{
|
||||
element *parent = m_open_tags.back ();
|
||||
parent->add_text (std::move (text));
|
||||
}
|
||||
|
||||
void
|
||||
printer::add_raw (std::string text)
|
||||
{
|
||||
element *parent = m_open_tags.back ();
|
||||
parent->add_child (std::make_unique<xml::raw> (std::move (text)));
|
||||
}
|
||||
|
||||
void
|
||||
printer::push_element (std::unique_ptr<element> new_element)
|
||||
{
|
||||
element *parent = m_open_tags.back ();
|
||||
m_open_tags.push_back (new_element.get ());
|
||||
parent->add_child (std::move (new_element));
|
||||
}
|
||||
|
||||
void
|
||||
printer::append (std::unique_ptr<node> new_node)
|
||||
{
|
||||
element *parent = m_open_tags.back ();
|
||||
parent->add_child (std::move (new_node));
|
||||
}
|
||||
|
||||
element *
|
||||
printer::get_insertion_point () const
|
||||
{
|
||||
return m_open_tags.back ();
|
||||
}
|
||||
|
||||
} // namespace xml
|
||||
|
||||
#if CHECKING_P
|
||||
|
||||
namespace selftest {
|
||||
|
||||
static void
|
||||
test_printer ()
|
||||
{
|
||||
xml::element top ("top", false);
|
||||
xml::printer xp (top);
|
||||
xp.push_tag ("foo");
|
||||
xp.add_text ("hello");
|
||||
xp.push_tag ("bar");
|
||||
xp.set_attr ("size", "3");
|
||||
xp.set_attr ("color", "red");
|
||||
xp.add_text ("world");
|
||||
xp.push_tag ("baz");
|
||||
xp.pop_tag ();
|
||||
xp.pop_tag ();
|
||||
xp.pop_tag ();
|
||||
|
||||
pretty_printer pp;
|
||||
top.write_as_xml (&pp, 0, true);
|
||||
ASSERT_STREQ
|
||||
(pp_formatted_text (&pp),
|
||||
"<top>\n"
|
||||
" <foo>\n"
|
||||
" hello\n"
|
||||
" <bar size=\"3\" color=\"red\">\n"
|
||||
" world\n"
|
||||
" <baz/>\n"
|
||||
" </bar>\n"
|
||||
" </foo>\n"
|
||||
"</top>\n");
|
||||
}
|
||||
|
||||
// Verify that element attributes preserve insertion order.
|
||||
|
||||
static void
|
||||
test_attribute_ordering ()
|
||||
{
|
||||
xml::element top ("top", false);
|
||||
xml::printer xp (top);
|
||||
xp.push_tag ("chronological");
|
||||
xp.set_attr ("maldon", "991");
|
||||
xp.set_attr ("hastings", "1066");
|
||||
xp.set_attr ("edgehill", "1642");
|
||||
xp.set_attr ("naseby", "1645");
|
||||
xp.pop_tag ();
|
||||
xp.push_tag ("alphabetical");
|
||||
xp.set_attr ("edgehill", "1642");
|
||||
xp.set_attr ("hastings", "1066");
|
||||
xp.set_attr ("maldon", "991");
|
||||
xp.set_attr ("naseby", "1645");
|
||||
xp.pop_tag ();
|
||||
|
||||
pretty_printer pp;
|
||||
top.write_as_xml (&pp, 0, true);
|
||||
ASSERT_STREQ
|
||||
(pp_formatted_text (&pp),
|
||||
"<top>\n"
|
||||
" <chronological maldon=\"991\" hastings=\"1066\" edgehill=\"1642\" naseby=\"1645\"/>\n"
|
||||
" <alphabetical edgehill=\"1642\" hastings=\"1066\" maldon=\"991\" naseby=\"1645\"/>\n"
|
||||
"</top>\n");
|
||||
}
|
||||
|
||||
/* Run all of the selftests within this file. */
|
||||
|
||||
void
|
||||
xml_cc_tests ()
|
||||
{
|
||||
test_printer ();
|
||||
test_attribute_ordering ();
|
||||
}
|
||||
|
||||
} // namespace selftest
|
||||
|
||||
#endif /* CHECKING_P */
|
||||
Reference in New Issue
Block a user