1 /*
2  *  Created by Phil on 09/12/2010.
3  *  Copyright 2010 Two Blue Cubes Ltd. All rights reserved.
4  *
5  *  Distributed under the Boost Software License, Version 1.0. (See accompanying
6  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7  */
8 #ifndef TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
9 #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
10 
11 #include "catch_stream.h"
12 #include "catch_compiler_capabilities.h"
13 
14 #include <vector>
15 
16 namespace Catch {
17     enum class XmlFormatting {
18         None = 0x00,
19         Indent = 0x01,
20         Newline = 0x02,
21     };
22 
23     XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs);
24     XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs);
25 
26     class XmlEncode {
27     public:
28         enum ForWhat { ForTextNodes, ForAttributes };
29 
30         XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes );
31 
32         void encodeTo( std::ostream& os ) const;
33 
34         friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
35 
36     private:
37         std::string m_str;
38         ForWhat m_forWhat;
39     };
40 
41     class XmlWriter {
42     public:
43 
44         class ScopedElement {
45         public:
46             ScopedElement( XmlWriter* writer, XmlFormatting fmt );
47 
48             ScopedElement( ScopedElement&& other ) noexcept;
49             ScopedElement& operator=( ScopedElement&& other ) noexcept;
50 
51             ~ScopedElement();
52 
53             ScopedElement& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent );
54 
55             template<typename T>
writeAttribute(std::string const & name,T const & attribute)56             ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
57                 m_writer->writeAttribute( name, attribute );
58                 return *this;
59             }
60 
61         private:
62             mutable XmlWriter* m_writer = nullptr;
63             XmlFormatting m_fmt;
64         };
65 
66         XmlWriter( std::ostream& os = Catch::cout() );
67         ~XmlWriter();
68 
69         XmlWriter( XmlWriter const& ) = delete;
70         XmlWriter& operator=( XmlWriter const& ) = delete;
71 
72         XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
73 
74         ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
75 
76         XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
77 
78         XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );
79 
80         XmlWriter& writeAttribute( std::string const& name, bool attribute );
81 
82         template<typename T>
writeAttribute(std::string const & name,T const & attribute)83         XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
84             ReusableStringStream rss;
85             rss << attribute;
86             return writeAttribute( name, rss.str() );
87         }
88 
89         XmlWriter& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
90 
91         XmlWriter& writeComment(std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
92 
93         void writeStylesheetRef( std::string const& url );
94 
95         XmlWriter& writeBlankLine();
96 
97         void ensureTagClosed();
98 
99     private:
100 
101         void applyFormatting(XmlFormatting fmt);
102 
103         void writeDeclaration();
104 
105         void newlineIfNecessary();
106 
107         bool m_tagIsOpen = false;
108         bool m_needsNewline = false;
109         std::vector<std::string> m_tags;
110         std::string m_indent;
111         std::ostream& m_os;
112     };
113 
114 }
115 
116 #endif // TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
117