9acbbe6a7977bdaa6123823858a9b53d9d65184b
[situare] / tests / coordinates / geocoordinate / testgeocoordinate.cpp
1 /*
2     Situare - A location system for Facebook
3     Copyright (C) 2010  Ixonos Plc. Authors:
4
5         Sami Rämö - sami.ramo@ixonos.com
6
7     Situare is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License
9     version 2 as published by the Free Software Foundation.
10
11     Situare is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with Situare; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
19     USA.
20 */
21
22 #include <QtCore/QString>
23 #include <QtTest/QtTest>
24
25 #include "coordinates/scenecoordinate.h"
26 #include "map/mapcommon.h"
27
28 #include "coordinates/geocoordinate.h"
29
30 const double LATITUDE = 12.345678;
31 const double LONGITUDE = -89.765432;
32
33 const double ONE_SCENE_PIXEL_WIDTH_IN_DEGREES = 0.00000536441802978516;
34
35 class TestGeoCoordinate : public QObject
36 {
37     Q_OBJECT
38
39 private Q_SLOTS:
40     void constructors();
41     void conversion();
42     void conversion_data();
43     void distanceTo();
44     void distanceTo_data();
45     void isNullAndIsValid();
46     void isValid();
47     void isValid_data();
48     void settersAndGetters();
49     void streamOperators();
50     void subtractOperator();
51 };
52
53 // for formatting the output of double valuest into the test log
54 namespace QTest {
55     template<>
56     char *toString(const double &number)
57     {
58         QByteArray ba;
59         ba += QByteArray::number(number, 'f', 9);
60         return qstrdup(ba.data());
61     }
62 }
63
64 void TestGeoCoordinate::constructors()
65 {
66     GeoCoordinate coordinate;
67     QVERIFY(coordinate.isNull());
68
69     GeoCoordinate coordinate2(LATITUDE, LONGITUDE);
70     QCOMPARE(coordinate2.latitude(), LATITUDE);
71     QCOMPARE(coordinate2.longitude(), LONGITUDE);
72
73     // NOTE: constructor with conversion from GeoCoordinate is tested in conversion() test slot
74 }
75
76 void TestGeoCoordinate::conversion()
77 {
78     // allow rounding error of one tenth of one scene pixel
79     const double MAX_ERROR = ONE_SCENE_PIXEL_WIDTH_IN_DEGREES * 0.1;
80
81     QFETCH(SceneCoordinate, sceneCoordinate);
82     QFETCH(GeoCoordinate, result);
83
84     GeoCoordinate geoCoordinate(sceneCoordinate);
85
86     QVERIFY(qAbs(geoCoordinate.latitude() - result.latitude()) < MAX_ERROR);
87     QVERIFY(qAbs(geoCoordinate.longitude() - result.longitude()) < MAX_ERROR);
88 }
89
90 void TestGeoCoordinate::conversion_data()
91 {
92     QTest::addColumn<SceneCoordinate>("sceneCoordinate");
93     QTest::addColumn<GeoCoordinate>("result");
94
95     QTest::newRow("top left") << SceneCoordinate(OSM_MAP_MIN_PIXEL_X, OSM_MAP_MIN_PIXEL_Y)
96                               << GeoCoordinate(OSM_MAX_LATITUDE, MIN_LONGITUDE);
97
98     const double LAST_SCENE_HORIZONTAL_PIXEL_LONGITUDE = MAX_LONGITUDE
99                                                          - ONE_SCENE_PIXEL_WIDTH_IN_DEGREES;
100
101     QTest::newRow("bottom right") << SceneCoordinate(OSM_MAP_MAX_PIXEL_X, OSM_MAP_MAX_PIXEL_Y)
102                                   << GeoCoordinate(OSM_MIN_LATITUDE,
103                                                    LAST_SCENE_HORIZONTAL_PIXEL_LONGITUDE);
104 }
105
106 void TestGeoCoordinate::distanceTo()
107 {
108     QFETCH(GeoCoordinate, from);
109     QFETCH(GeoCoordinate, to);
110     QFETCH(qreal, expectedDistance);
111
112     QCOMPARE(from.distanceTo(to), expectedDistance);
113 }
114
115 void TestGeoCoordinate::distanceTo_data()
116 {
117     const qreal EARTH_RADIUS = 6371010; // in meters
118
119     QTest::addColumn<GeoCoordinate>("from");
120     QTest::addColumn<GeoCoordinate>("to");
121     QTest::addColumn<qreal>("expectedDistance");
122
123     QTest::newRow("longitude") << GeoCoordinate(0, -90)
124                                << GeoCoordinate(0, 90)
125                                << M_PI * 2 * EARTH_RADIUS / 2;
126
127     QTest::newRow("latitude") << GeoCoordinate(-45, 0)
128                               << GeoCoordinate(45, 0)
129                               << M_PI * 2 * EARTH_RADIUS / 4;
130
131     QTest::newRow("both") << GeoCoordinate(-25, -135)
132                           << GeoCoordinate(25, 45)
133                           << M_PI * 2 * EARTH_RADIUS / 2;
134 }
135
136
137 void TestGeoCoordinate::isNullAndIsValid()
138 {
139     // coordinate created with default constructor
140     GeoCoordinate coordinate;
141     QVERIFY(coordinate.isNull());
142     QVERIFY(!coordinate.isValid());
143
144     // only latitude is set
145     coordinate.setLatitude(LATITUDE);
146     QVERIFY(!coordinate.isNull());
147     QVERIFY(!coordinate.isValid());
148
149     // another coordinate created with default constructor
150     GeoCoordinate coordinate2;
151     QVERIFY(coordinate2.isNull());
152     QVERIFY(!coordinate2.isValid());
153
154     // only longitude is set
155     coordinate2.setLongitude(LONGITUDE);
156     QVERIFY(!coordinate2.isNull());
157     QVERIFY(!coordinate2.isValid());
158
159     // also latitude is set
160     coordinate2.setLatitude(LATITUDE);
161     QVERIFY(!coordinate2.isNull());
162     QVERIFY(coordinate2.isValid());
163
164     // null coordinate created with latitude and longitude parameters
165     GeoCoordinate coordinate3(0, 0);
166     QVERIFY(coordinate3.isNull());
167     QVERIFY(coordinate3.isValid());
168
169     // non-null coordinate created from scene coordinate
170     GeoCoordinate coordinate4 = GeoCoordinate(SceneCoordinate(1, 1));
171     QVERIFY(!coordinate4.isNull());
172     QVERIFY(coordinate4.isValid());
173
174     // non-null coordinate created with latitude and longitude parameters
175     GeoCoordinate coordinate5(LATITUDE, LONGITUDE);
176     QVERIFY(!coordinate5.isNull());
177     QVERIFY(coordinate5.isValid());
178 }
179
180 void TestGeoCoordinate::isValid()
181 {
182     QFETCH(GeoCoordinate, coordinate);
183     QFETCH(bool, expectedValidity);
184
185     QCOMPARE(coordinate.isValid(), expectedValidity);
186 }
187
188 void TestGeoCoordinate::isValid_data()
189 {
190     QTest::addColumn<GeoCoordinate>("coordinate");
191     QTest::addColumn<bool>("expectedValidity");
192
193     QTest::newRow("null") << GeoCoordinate(0, 0) << true;
194     QTest::newRow("min latitude") << GeoCoordinate(-90, 0) << true;
195     QTest::newRow("latitude too small") << GeoCoordinate(-90.000000001, 0) << false;
196     QTest::newRow("max latitude") << GeoCoordinate(90, 0) << true;
197     QTest::newRow("latitude too big") << GeoCoordinate(90.000000001, 0) << false;
198     QTest::newRow("min longitude") << GeoCoordinate(0, -180) << true;
199     QTest::newRow("longitude too small") << GeoCoordinate(0, -180.0000000001) << false;
200     QTest::newRow("max longitude") << GeoCoordinate(0, 180) << true;
201     QTest::newRow("longitude too big") << GeoCoordinate(0, 180.0000000001) << false;
202 }
203
204 void TestGeoCoordinate::settersAndGetters()
205 {
206     GeoCoordinate coordinate;
207     QCOMPARE(coordinate.latitude(), (double)0);
208     QCOMPARE(coordinate.longitude(), (double)0);
209
210     coordinate.setLatitude(LATITUDE);
211     coordinate.setLongitude(LONGITUDE);
212
213     QCOMPARE(coordinate.latitude(), LATITUDE);
214     QCOMPARE(coordinate.longitude(), LONGITUDE);
215 }
216
217 void TestGeoCoordinate::streamOperators()
218 {
219     // test data
220     GeoCoordinate original(LATITUDE, LONGITUDE);
221     GeoCoordinate originalInverted(LONGITUDE, LATITUDE);
222
223     // create data output stream and write coordinates to it
224     QByteArray array;
225     QDataStream outStream(&array,QIODevice::WriteOnly);
226     outStream << original << originalInverted;
227
228     // use another stream with same byte array for reading the values
229     QDataStream inStream(&array,QIODevice::ReadOnly);
230     GeoCoordinate another;
231     GeoCoordinate anotherInverted;
232     inStream >> another >> anotherInverted;
233
234     QCOMPARE(another.latitude(), original.latitude());
235     QCOMPARE(another.longitude(), original.longitude());
236     QCOMPARE(anotherInverted.latitude(), originalInverted.latitude());
237     QCOMPARE(anotherInverted.longitude(), originalInverted.longitude());
238 }
239
240 void TestGeoCoordinate::subtractOperator()
241 {
242     // test operator-
243     GeoCoordinate first(100, 50);
244     GeoCoordinate second(45, 15);
245
246     GeoCoordinate result = first - second;
247
248     QCOMPARE(result.latitude(), 55.0);
249     QCOMPARE(result.longitude(), 35.0);
250
251     // make sure the returned object is not either of the parameters
252     QVERIFY(&result != &first);
253     QVERIFY(&result != &second);
254 }
255
256 QTEST_APPLESS_MAIN(TestGeoCoordinate);
257
258 #include "testgeocoordinate.moc"