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