Add a class for parsing simple markup.
[wxWidgets.git] / tests / controls / markuptest.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/controls/markup.cpp
3 // Purpose: wxMarkupParser and related classes unit tests
4 // Author: Vadim Zeitlin
5 // Created: 2011-02-17
6 // RCS-ID: $Id$
7 // Copyright: (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #include "testprec.h"
11
12 #ifdef __BORLANDC__
13 #pragma hdrstop
14 #endif
15
16 #ifndef WX_PRECOMP
17 #endif // WX_PRECOMP
18
19 #include "wx/private/markupparser.h"
20
21 class MarkupTestCase : public CppUnit::TestCase
22 {
23 public:
24 MarkupTestCase() { }
25
26 private:
27 CPPUNIT_TEST_SUITE( MarkupTestCase );
28 CPPUNIT_TEST( RoundTrip );
29 CPPUNIT_TEST( Quote );
30 CPPUNIT_TEST_SUITE_END();
31
32 void RoundTrip();
33 void Quote();
34
35 wxDECLARE_NO_COPY_CLASS(MarkupTestCase);
36 };
37
38 // register in the unnamed registry so that these tests are run by default
39 CPPUNIT_TEST_SUITE_REGISTRATION( MarkupTestCase );
40
41 // also include in it's own registry so that these tests can be run alone
42 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( MarkupTestCase, "MarkupTestCase" );
43
44 void MarkupTestCase::RoundTrip()
45 {
46 // Define a wxMarkupParserOutput object which produces the same markup
47 // string on output. This is, of course, perfectly useless, but allows us
48 // to test that parsing works as expected.
49 class RoundTripOutput : public wxMarkupParserOutput
50 {
51 public:
52 RoundTripOutput() { }
53
54 void Reset() { m_text.clear(); }
55
56 const wxString& GetText() const { return m_text; }
57
58
59 virtual void OnText(const wxString& text) { m_text += text; }
60
61 virtual void OnBoldStart() { m_text += "<b>"; }
62 virtual void OnBoldEnd() { m_text += "</b>"; }
63
64 virtual void OnItalicStart() { m_text += "<i>"; }
65 virtual void OnItalicEnd() { m_text += "</i>"; }
66
67 virtual void OnUnderlinedStart() { m_text += "<u>"; }
68 virtual void OnUnderlinedEnd() { m_text += "</u>"; }
69
70 virtual void OnStrikethroughStart() { m_text += "<s>"; }
71 virtual void OnStrikethroughEnd() { m_text += "</s>"; }
72
73 virtual void OnBigStart() { m_text += "<big>"; }
74 virtual void OnBigEnd() { m_text += "</big>"; }
75
76 virtual void OnSmallStart() { m_text += "<small>"; }
77 virtual void OnSmallEnd() { m_text += "</small>"; }
78
79 virtual void OnTeletypeStart() { m_text += "<tt>"; }
80 virtual void OnTeletypeEnd() { m_text += "</tt>"; }
81
82 virtual void OnSpanStart(const wxMarkupSpanAttributes& attrs)
83 {
84 m_text << "<span";
85
86 if ( !attrs.m_fgCol.empty() )
87 m_text << " foreground=\"" << attrs.m_fgCol << "\"";
88
89 if ( !attrs.m_bgCol.empty() )
90 m_text << " background=\"" << attrs.m_bgCol << "\"";
91
92 if ( !attrs.m_fontFace.empty() )
93 m_text << " face=\"" << attrs.m_fontFace << "\"";
94
95 wxString size;
96 switch ( attrs.m_sizeKind )
97 {
98 case wxMarkupSpanAttributes::Size_Unspecified:
99 break;
100
101 case wxMarkupSpanAttributes::Size_Relative:
102 size << (attrs.m_fontSize > 0 ? "larger" : "smaller");
103 break;
104
105 case wxMarkupSpanAttributes::Size_Symbolic:
106 {
107 CPPUNIT_ASSERT( attrs.m_fontSize >= -3 &&
108 attrs.m_fontSize <= 3 );
109 static const char *cssSizes[] =
110 {
111 "xx-small", "x-small", "small",
112 "medium",
113 "large", "x-large", "xx-large",
114 };
115
116 size << cssSizes[attrs.m_fontSize + 3];
117 }
118 break;
119
120 case wxMarkupSpanAttributes::Size_PointParts:
121 size.Printf("%u", attrs.m_fontSize);
122 break;
123 }
124
125 if ( !size.empty() )
126 m_text << " size=\"" << size << '"';
127
128 // TODO: Handle the rest of attributes.
129
130 m_text << ">";
131 }
132
133 virtual void OnSpanEnd(const wxMarkupSpanAttributes& WXUNUSED(attrs))
134 {
135 m_text += "</span>";
136 }
137
138 private:
139 wxString m_text;
140 };
141
142
143 RoundTripOutput output;
144 wxMarkupParser parser(output);
145
146 #define CHECK_PARSES_OK(text) \
147 output.Reset(); \
148 CPPUNIT_ASSERT( parser.Parse(text) ); \
149 CPPUNIT_ASSERT_EQUAL( text, output.GetText() )
150
151 #define CHECK_PARSES_AS(text, result) \
152 output.Reset(); \
153 CPPUNIT_ASSERT( parser.Parse(text) ); \
154 CPPUNIT_ASSERT_EQUAL( result, output.GetText() )
155
156 #define CHECK_DOESNT_PARSE(text) \
157 CPPUNIT_ASSERT( !parser.Parse(text) )
158
159 CHECK_PARSES_OK( "" );
160 CHECK_PARSES_OK( "foo" );
161 CHECK_PARSES_OK( "foo<b>bar</b>" );
162 CHECK_PARSES_OK( "1<big>2<small>3</small>4<big>5</big></big>6" );
163 CHECK_PARSES_OK( "first <span foreground=\"red\">second</span> last" );
164 CHECK_PARSES_OK( "first <span foreground=\"red\" "
165 "background=\"#ffffff\">second </span> last" );
166 CHECK_PARSES_OK( "<span size=\"10240\">10pt</span>" );
167 CHECK_PARSES_OK( "<span size=\"x-small\">much smaller</span>" );
168 CHECK_PARSES_OK( "<span size=\"larger\">larger</span>" );
169 CHECK_PARSES_OK
170 (
171 "<u>Please</u> notice: <i><b>any</b></i> <span foreground=\"grey\">"
172 "<s><tt>bugs</tt></s></span> in this code are <span foreground=\"red\" "
173 "size=\"xx-large\">NOT</span> allowed."
174 );
175
176 CHECK_PARSES_OK( "foo&bar" );
177 CHECK_PARSES_AS( "foo&amp;bar", "foo&&bar" );
178 CHECK_PARSES_AS( "&lt;O&apos;Reilly&gt;", "<O'Reilly>" );
179
180 CHECK_DOESNT_PARSE( "<" );
181 CHECK_DOESNT_PARSE( "<b" );
182 CHECK_DOESNT_PARSE( "<b>" );
183 CHECK_DOESNT_PARSE( "<b></i>" );
184 CHECK_DOESNT_PARSE( "<b><i></b></i>" );
185 CHECK_DOESNT_PARSE( "<foo></foo>" );
186
187 #undef CHECK_PARSES_OK
188 #undef CHECK_DOESNT_PARSE
189 }
190
191 void MarkupTestCase::Quote()
192 {
193 CPPUNIT_ASSERT_EQUAL( "", wxMarkupParser::Quote("") );
194 CPPUNIT_ASSERT_EQUAL( "foo", wxMarkupParser::Quote("foo") );
195 CPPUNIT_ASSERT_EQUAL( "&lt;foo&gt;", wxMarkupParser::Quote("<foo>") );
196 CPPUNIT_ASSERT_EQUAL( "B&amp;B", wxMarkupParser::Quote("B&B") );
197 CPPUNIT_ASSERT_EQUAL( "&quot;&quot;", wxMarkupParser::Quote("\"\"") );
198 }