1 // Copyright 2008, Google Inc. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are met:
5 //
6 // 1. Redistributions of source code must retain the above copyright notice,
7 // this list of conditions and the following disclaimer.
8 // 2. Redistributions in binary form must reproduce the above copyright notice,
9 // this list of conditions and the following disclaimer in the documentation
10 // and/or other materials provided with the distribution.
11 // 3. Neither the name of Google Inc. nor the names of its contributors may be
12 // used to endorse or promote products derived from this software without
13 // specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26 #include "kml/dom/kml22.h"
27 #include "kml/dom/kml_factory.h"
28 #include "kml/dom/kml_ptr.h"
29 #include "kml/dom/xsd.h"
30 #include "kml/dom/serializer.h"
31 #include "gtest/gtest.h"
32
33 namespace kmldom {
34
35 // Yes, must exactly match kml22.h
36 static const int kNumberOfComplexElements = 92;
37
38 class Kml22Test : public testing::Test {
39 protected:
SetUp()40 virtual void SetUp() {
41 xsd_ = Xsd::GetSchema();
42 }
43
44 Xsd* xsd_;
45
46 void AssertXmlNamespaceForRange(KmlDomType begin_id, KmlDomType end_id,
47 kmlbase::XmlnsId xmlns_id);
48 };
49
50 // Verify proper enum defaults:
TEST_F(Kml22Test,TestEnumDefaults)51 TEST_F(Kml22Test, TestEnumDefaults) {
52 ASSERT_EQ(string("clampToGround"),
53 xsd_->EnumValue(Type_altitudeMode, ALTITUDEMODE_CLAMPTOGROUND));
54 ASSERT_EQ(string("normal"),
55 xsd_->EnumValue(Type_colorMode, COLORMODE_NORMAL));
56 ASSERT_EQ(string("default"),
57 xsd_->EnumValue(Type_displayMode, DISPLAYMODE_DEFAULT));
58 ASSERT_EQ(string("lowerLeft"),
59 xsd_->EnumValue(Type_gridOrigin, GRIDORIGIN_LOWERLEFT));
60 ASSERT_EQ(string("open"),
61 xsd_->EnumValue(Type_state, ITEMICONSTATE_OPEN));
62 ASSERT_EQ(string("check"),
63 xsd_->EnumValue(Type_listItemType, LISTITEMTYPE_CHECK));
64 ASSERT_EQ(string("onChange"),
65 xsd_->EnumValue(Type_refreshMode, REFRESHMODE_ONCHANGE));
66 ASSERT_EQ(string("rectangle"),
67 xsd_->EnumValue(Type_shape, SHAPE_RECTANGLE));
68 ASSERT_EQ(string("normal"),
69 xsd_->EnumValue(Type_key, STYLESTATE_NORMAL));
70 ASSERT_EQ(string("fraction"),
71 xsd_->EnumValue(Type_units, UNITS_FRACTION));
72 ASSERT_EQ(string("never"),
73 xsd_->EnumValue(Type_viewRefreshMode, VIEWREFRESHMODE_NEVER));
74 ASSERT_EQ(string("bounce"),
75 xsd_->EnumValue(Type_GxFlyToMode, GX_FLYTOMODE_BOUNCE));
76 ASSERT_EQ(string("pause"),
77 xsd_->EnumValue(Type_GxPlayMode, GX_PLAYMODE_PAUSE));
78 }
79
80 // Test NULL arg on AddElement(), ParseAttributes(), and SerializeAttributes()
81 // on all complex elements. These are all methods that take pointer arguments.
TEST_F(Kml22Test,TestElementNull)82 TEST_F(Kml22Test, TestElementNull) {
83 int complex_count = 0;
84 int element_type_id = static_cast<int>(Type_Unknown) + 1;
85 const int end_id = static_cast<int>(Type_Invalid);
86 KmlFactory* kml_factory = KmlFactory::GetFactory();
87 for (; element_type_id != end_id; ++element_type_id) {
88 // Only complex elements return non-NULL.
89 if (ElementPtr element = kml_factory->CreateElementById(
90 static_cast<KmlDomType>(element_type_id))) {
91 // All KmlFactory-created elements are known.
92 ASSERT_FALSE(element->IsA(kmldom::Type_Unknown));
93 // Verify the element's abstract base types.
94 if (element->IsA(kmldom::Type_ColorStyle)) {
95 ASSERT_TRUE(element->IsA(kmldom::Type_SubStyle));
96 }
97 if (element->IsA(kmldom::Type_Container)) {
98 ASSERT_TRUE(element->IsA(kmldom::Type_Feature));
99 }
100 if (element->IsA(kmldom::Type_Overlay)) {
101 ASSERT_TRUE(element->IsA(kmldom::Type_Feature));
102 }
103 if (element->IsA(kmldom::Type_AbstractLatLonBox) ||
104 element->IsA(kmldom::Type_AbstractView) ||
105 element->IsA(kmldom::Type_BasicLink) ||
106 element->IsA(kmldom::Type_Feature) ||
107 element->IsA(kmldom::Type_Geometry) ||
108 element->IsA(kmldom::Type_StyleSelector) ||
109 element->IsA(kmldom::Type_SubStyle) ||
110 element->IsA(kmldom::Type_TimePrimitive)) {
111 ASSERT_TRUE(element->IsA(kmldom::Type_Object));
112 }
113 // Verify NULL pointers do no harm.
114 element->AddElement(NULL);
115 element->ParseAttributes(NULL);
116 element->SerializeAttributes(NULL);
117 ++complex_count;
118 }
119 }
120 ASSERT_EQ(kNumberOfComplexElements, complex_count);
121 }
122
123 // This Serializer is specifically designed to capture the output of the
124 // serialization of any complex element.
125 class MockElementSerializer : public Serializer {
126 public:
MockElementSerializer()127 MockElementSerializer()
128 : begin_count_(0),
129 end_count_(0),
130 type_id_(Type_Invalid) {
131 }
BeginById(int type_id,const kmlbase::Attributes & attributes)132 virtual void BeginById(int type_id, const kmlbase::Attributes& attributes) {
133 ++begin_count_;
134 type_id_ = type_id;
135 }
End()136 virtual void End() {
137 ++end_count_;
138 }
get_type_id() const139 int get_type_id() const {
140 return type_id_;
141 }
get_begin_count() const142 int get_begin_count() const {
143 return begin_count_;
144 }
get_end_count() const145 int get_end_count() const {
146 return end_count_;
147 }
148 private:
149 int begin_count_;
150 int end_count_;
151 int type_id_;
152 };
153
154 // This calls the Serialize method on every complex element on the
155 // MockElementSerializer to verify that Serialize always emits BeginById() with
156 // the expected element type id and always emits End() and both exactly once.
TEST_F(Kml22Test,TestElementSerializerEmpty)157 TEST_F(Kml22Test, TestElementSerializerEmpty) {
158 int complex_count = 0;
159 int element_type_id = static_cast<int>(Type_Unknown) + 1;
160 const int end_id = static_cast<int>(Type_Invalid);
161 KmlFactory* kml_factory = KmlFactory::GetFactory();
162 for (; element_type_id != end_id; ++element_type_id) {
163 // Only complex elements return non-NULL.
164 if (ElementPtr element = kml_factory->CreateElementById(
165 static_cast<KmlDomType>(element_type_id))) {
166 // Every complex element has a Serialize method that further calls
167 // BeginById(type), and End().
168 MockElementSerializer mock;
169 element->Serialize(mock);
170 ASSERT_EQ(element->Type(), mock.get_type_id());
171 ASSERT_EQ(1, mock.get_begin_count());
172 ASSERT_EQ(1, mock.get_end_count());
173 ++complex_count;
174 }
175 }
176 ASSERT_EQ(kNumberOfComplexElements, complex_count);
177 }
178
AssertXmlNamespaceForRange(KmlDomType begin_dom_type,KmlDomType end_dom_type,kmlbase::XmlnsId xmlns_id)179 void Kml22Test::AssertXmlNamespaceForRange(KmlDomType begin_dom_type,
180 KmlDomType end_dom_type,
181 kmlbase::XmlnsId xmlns_id) {
182 // There's obviously an assumption here about the organization of the
183 // KmlDomType enum
184 int element_type_id = static_cast<int>(begin_dom_type);
185 const int end_id = static_cast<int>(end_dom_type) + 1;
186 KmlFactory* kml_factory = KmlFactory::GetFactory();
187 for (; element_type_id != end_id; ++element_type_id) {
188 ElementPtr element = kml_factory->CreateElementById(
189 static_cast<KmlDomType>(element_type_id));
190 ASSERT_TRUE(element);
191 ASSERT_EQ(xmlns_id, element->get_xmlns())
192 << xsd_->ElementName(element_type_id);
193 }
194 }
195
TEST_F(Kml22Test,TestElementXmlNamespaces)196 TEST_F(Kml22Test, TestElementXmlNamespaces) {
197 AssertXmlNamespaceForRange(Type_Alias, Type_ViewVolume,
198 kmlbase::XMLNS_KML22);
199 AssertXmlNamespaceForRange(Type_AtomAuthor, Type_AtomLink,
200 kmlbase::XMLNS_ATOM);
201 AssertXmlNamespaceForRange(Type_XalAddressDetails, Type_XalThoroughfare,
202 kmlbase::XMLNS_XAL);
203 AssertXmlNamespaceForRange(Type_GxAnimatedUpdate, Type_GxWait,
204 kmlbase::XMLNS_GX22);
205 }
206
207 // Every complex element preserves unknown children.
TEST_F(Kml22Test,TestSaveUnknown)208 TEST_F(Kml22Test, TestSaveUnknown) {
209 int complex_count = 0;
210 int element_type_id = static_cast<int>(Type_Unknown) + 1;
211 const int end_id = static_cast<int>(Type_Invalid);
212 KmlFactory* kml_factory = KmlFactory::GetFactory();
213 for (; element_type_id != end_id; ++element_type_id) {
214 // Only complex elements return non-NULL.
215 if (ElementPtr element = kml_factory->CreateElementById(
216 static_cast<KmlDomType>(element_type_id))) {
217 ++complex_count;
218 }
219 }
220 ASSERT_EQ(kNumberOfComplexElements, complex_count);
221 }
222
223 } // end namespace kmldom
224