1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2014 Calin Cruceru <calin@rosedu.org>
4 //
5 
6 #include <QObject>
7 
8 #include "GeoDataContainer.h"
9 #include "GeoDataPoint.h"
10 #include "GeoDataPlacemark.h"
11 #include "GeoDataRelation.h"
12 #include "GeoDataCamera.h"
13 #include "MarbleGlobal.h"
14 #include "GeoDataPlaylist.h"
15 #include "GeoDataTour.h"
16 #include "TestUtils.h"
17 
18 
19 namespace Marble
20 {
21 
22 class TestFeatureDetach : public QObject
23 {
24     Q_OBJECT
25 
26 private Q_SLOTS:
27     /**
28      * FIXME: Doesn't work for the moment because calling detach() in
29      * GeoDataFeature::set/abstractView() doesn't help because the object
30      * isn't deep-copied in the private class.
31      *
32      * @brief testRelation shows that getting the abstractView() of a copied
33      * feature and modifying it doesn't modify the original one.
34      */
35     void testRelation();
36 
37     /**
38      * @brief testDocument shows that getting some child and modifying it,
39      * doesn't modify the child at the same position in the original container.
40      */
41     void testDocument();
42 
43     /**
44      * @brief testPlacemark shows that getting the geometry() and modifying it
45      * doesn't modify the geometry of the original placemark.
46      */
47     void testPlacemark();
48 
49     /**
50      * @brief testTour shows that modifying the playlist of a copied tour doesn't
51      * modify the playlist of the original one.
52      */
53     void testTour();
54 
55     /**
56      * @brief testGeometryParentInPlacemark shows that copying a placemark correctly
57      * keeps the geometries of both the copied one and the original one pointing to its
58      * parent. Before the changes made in GeoDataPlacemark (calling setParent() after
59      * each detach() call and not calling anymore in the
60      * GeoDataPlacemark( const GeoDataGeometry &other ) constructor), after the operation
61      * highlighted in this test, the geometry of the first one (the original one) ended
62      * pointing (its parent) to the second placemark and the second one had its geometry's
63      * parent a null pointer.
64      */
65     void testGeometryParentInPlacemark();
66 
67 };
68 
testRelation()69 void TestFeatureDetach::testRelation()
70 {
71     GeoDataRelation feat1;
72     GeoDataCamera *view1 = new GeoDataCamera();
73     view1->setAltitudeMode(Absolute);
74     feat1.setAbstractView(view1);
75 
76     GeoDataRelation feat2 = feat1;
77     feat2.abstractView()->setAltitudeMode(ClampToSeaFloor);
78     // FIXME: See above (method description).
79     // QVERIFY(feat1.abstractView()->altitudeMode() == Absolute);
80 }
81 
testDocument()82 void TestFeatureDetach::testDocument()
83 {
84     GeoDataDocument cont1;
85     GeoDataFeature *feat1 = new GeoDataPlacemark();
86     feat1->setName("Feat1");
87     cont1.insert(0, feat1);
88 
89     GeoDataDocument cont2 = cont1;
90     cont2.child(0)->setName("Feat2");
91     QCOMPARE(cont1.child(0)->name(), QLatin1String("Feat1"));
92 
93     const GeoDataDocument cont3 = cont1;
94     QCOMPARE(cont3.child(0)->name(), QLatin1String("Feat1"));
95 }
96 
testPlacemark()97 void TestFeatureDetach::testPlacemark()
98 {
99     GeoDataCoordinates coords1(30, 30, 0, GeoDataCoordinates::Degree);
100     GeoDataPlacemark place1;
101     place1.setCoordinate(coords1);
102 
103     GeoDataPlacemark place2 = place1;
104 
105     GeoDataCoordinates coords2(60, 60, 0, GeoDataCoordinates::Degree);
106     GeoDataPoint *point = static_cast<GeoDataPoint*>( place2.geometry() );
107     point->setCoordinates(coords2);
108     QVERIFY(place1.coordinate() == coords1);
109 
110     const GeoDataPlacemark place3 = place1;
111     QVERIFY(place3.coordinate() == coords1);
112 }
113 
testTour()114 void TestFeatureDetach::testTour()
115 {
116     GeoDataPlaylist *newPlaylist = new GeoDataPlaylist;
117     newPlaylist->setId("Playlist1");
118     GeoDataTour tour1;
119     tour1.setPlaylist(newPlaylist);
120 
121     GeoDataTour tour2 = tour1;
122     tour2.playlist()->setId("Playlist2");
123     QCOMPARE(tour1.playlist()->id(), QLatin1String("Playlist1"));
124 
125     const GeoDataTour tour3 = tour1;
126     QCOMPARE(tour3.playlist()->id(), QLatin1String("Playlist1"));
127 }
128 
testGeometryParentInPlacemark()129 void TestFeatureDetach::testGeometryParentInPlacemark()
130 {
131     GeoDataPlacemark place1;
132     QVERIFY(place1.geometry()->parent() == &place1);
133 
134     GeoDataPlacemark place2 = place1;
135 
136     // With the changes (regarding setParent() multiple calls after each
137     // detach() call) the only moment when some invariant is broken is right now,
138     // after the copy constructor has been called and no other method (which calls
139     // detach()) hasn't. This is because the geometry is not immediately copied,
140     // so the geometry of place2 has as parent place1. This is immediately solved
141     // when calling geometry() below.
142     QVERIFY(place2.geometry()->parent() == &place2);
143     QVERIFY(place1.geometry()->parent() == &place1);
144 }
145 
146 }
147 
148 QTEST_MAIN( Marble::TestFeatureDetach )
149 
150 #include "TestFeatureDetach.moc"
151