1 /*
2     SPDX-FileCopyrightText: 2016 Akarsh Simha <akarsh.simha@kdemail.net>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "testcachingdms.h"
8 
9 #include "auxiliary/cachingdms.h"
10 
11 #include <QtTest>
12 
13 #include <ctime>
14 #include <cstdlib>
15 #include <cstdint>
16 
TestCachingDms()17 TestCachingDms::TestCachingDms() : QObject()
18 {
19 }
20 
defaultCtor()21 void TestCachingDms::defaultCtor()
22 {
23     /*
24      * Test 1: Check Default Constructor
25     */
26 
27     // Check default empty constructor
28     CachingDms d;
29     QVERIFY(std::isnan(d.Degrees()));
30     QVERIFY(std::isnan(d.sin()));
31     QVERIFY(std::isnan(d.cos()));
32 }
33 
explicitSexigesimalCtor()34 void TestCachingDms::explicitSexigesimalCtor()
35 {
36     /*
37      * Test 2: Checks Sexigesimal Ctor
38     */
39 
40     // DD:MM:SS
41     // 14:55:20
42 
43     CachingDms d(14, 55, 20);
44 
45     QVERIFY(d.degree() == 14);
46     QVERIFY(d.arcmin() == 55);
47     QVERIFY(d.arcsec() == 20);
48     QVERIFY(qFuzzyCompare(d.Degrees(), (14.0 + 55.0 / 60.0 + 20.0 / 3600.0)));
49     QVERIFY(fabs(d.sin() - .25750758368074941632) < 1e-9);
50     QVERIFY(fabs(d.cos() - .96627627744186177805) < 1e-9);
51 }
52 
angleCtor()53 void TestCachingDms::angleCtor()
54 {
55     /*
56      * Test 3: Checks Angle Ctor
57     */
58 
59     // Angle = -112.56 Degrees ---> HMS (16:29:45)
60 
61     double angle = -112.56;
62 
63     CachingDms d(angle);
64 
65     QVERIFY(d.degree() == (int)angle);
66 
67     QVERIFY(qFuzzyCompare(d.Hours(), (angle + 360) / 15.0));
68     QVERIFY(d.hour() == 16);
69     QVERIFY(d.minute() == 29);
70     QVERIFY(d.second() == 45);
71     QVERIFY(fabs(d.sin() + 0.92347828085768229015) < 1e-9);
72     QVERIFY(fabs(d.cos() + 0.38365070674265630377) < 1e-9);
73 }
74 
stringCtor()75 void TestCachingDms::stringCtor()
76 {
77     QString hms("14:55:20");
78 
79     // From Degree
80     CachingDms d(hms);
81 
82     QVERIFY(d.degree() == 14);
83     QVERIFY(d.arcmin() == 55);
84     QVERIFY(d.arcsec() == 20);
85     QVERIFY(qFuzzyCompare(d.Degrees(), (14.0 + 55.0 / 60.0 + 20.0 / 3600.0)));
86     QVERIFY(fabs(d.sin() - .25750758368074941632) < 1e-9);
87     QVERIFY(fabs(d.cos() - .96627627744186177805) < 1e-9);
88 
89     // From Hours
90     CachingDms h(hms, false);
91     QVERIFY(qFuzzyCompare(h.Degrees(), d.Degrees() * 15.0));
92     QVERIFY(qFuzzyCompare(h.Hours(), d.Degrees()));
93 }
94 
setUsing_asin()95 void TestCachingDms::setUsing_asin()
96 {
97     // Test case in first quadrant: 56.3 degrees
98     CachingDms d;
99     d.setUsing_asin(.83195412213048254606);
100     QVERIFY(fabs(d.Degrees() - 56.3) < 1e-7);
101     QVERIFY(fabs(d.cos() - .55484442744799927555) < 1e-9);
102 
103     // Test case in fourth quadrant: -56.3 degrees
104     d.setUsing_asin(-.83195412213048254606);
105     QVERIFY(fabs(d.Degrees() + 56.3) < 1e-7);
106     QVERIFY(fabs(d.cos() - .55484442744799927555) < 1e-9);
107 }
108 
setUsing_acos()109 void TestCachingDms::setUsing_acos()
110 {
111     CachingDms d;
112 
113     // Test case in first quadrant: 56.3 degrees
114     d.setUsing_acos(.55484442744799927555);
115     QVERIFY(fabs(d.Degrees() - 56.3) < 1e-7);
116     QVERIFY(fabs(d.sin() - .83195412213048254606) < 1e-9);
117 
118     // Test case in second quadrant: 123.7 degrees
119     d.setUsing_acos(-0.55484442744799927555);
120     QVERIFY(fabs(d.Degrees() - 123.7) < 1e-7);
121     QVERIFY(fabs(d.sin() - .83195412213048254606) < 1e-9);
122 }
123 
setUsing_atan2()124 void TestCachingDms::setUsing_atan2()
125 {
126     // Test case in first quadrant: 56.3 degrees
127     CachingDms d;
128     d.setUsing_atan2(2.73701935509448143467, 1.82536500102022632674);
129     QVERIFY(fabs(d.Degrees() - 56.3) < 1e-7);
130     QVERIFY(fabs(d.sin() - .83195412213048254606) < 1e-9);
131     QVERIFY(fabs(d.cos() - .55484442744799927555) < 1e-9);
132 
133     // Test case in third quadrant: -123.7 degrees
134     d.setUsing_atan2(-2.73701935509448143467, -1.82536500102022632674);
135     QVERIFY(fabs(d.Degrees() + 123.7) < 1e-7);
136     QVERIFY(fabs(d.sin() + .83195412213048254606) < 1e-9);
137     QVERIFY(fabs(d.cos() + .55484442744799927555) < 1e-9);
138 
139     // Test case in second quadrant: 123.7 degrees
140     d.setUsing_atan2(2.73701935509448143467, -1.82536500102022632674);
141     QVERIFY(fabs(d.Degrees() - 123.7) < 1e-7);
142     QVERIFY(fabs(d.sin() - .83195412213048254606) < 1e-9);
143     QVERIFY(fabs(d.cos() + .55484442744799927555) < 1e-9);
144 
145     // Test case in fourth quadrant: -56.3 degrees
146     d.setUsing_atan2(-2.73701935509448143467, +1.82536500102022632674);
147     QVERIFY(fabs(d.Degrees() + 56.3) < 1e-7);
148     QVERIFY(fabs(d.sin() + .83195412213048254606) < 1e-9);
149     QVERIFY(fabs(d.cos() - .55484442744799927555) < 1e-9);
150 
151     // Edge case test: angle = 0
152     d.setUsing_atan2(0., 1.33);
153     QVERIFY(fabs(d.Degrees() - 0.) < 1e-7);
154     QVERIFY(fabs(d.sin() - 0.) < 1e-9);
155     QVERIFY(fabs(d.cos() - 1.) < 1e-9);
156 
157     // Edge case test: angle = 90 degrees
158     d.setUsing_atan2(10.12, 0.);
159     QVERIFY(fabs(d.Degrees() - 90.) < 1e-7);
160     QVERIFY(fabs(d.sin() - 1.) < 1e-9);
161     QVERIFY(fabs(d.cos() - 0.) < 1e-9);
162 
163     // Edge case test: angle = -90 degrees
164     d.setUsing_atan2(-3.1415, 0.);
165     QVERIFY(fabs(d.Degrees() + 90.) < 1e-7);
166     QVERIFY(fabs(d.sin() + 1.) < 1e-9);
167     QVERIFY(fabs(d.cos() - 0.) < 1e-9);
168 
169     // Edge case test: angle = 180 degrees
170     d.setUsing_atan2(0., -724.);
171     QVERIFY(fabs(d.Degrees() - 180.) < 1e-7);
172     QVERIFY(fabs(d.sin() - 0.) < 1e-9);
173     QVERIFY(fabs(d.cos() + 1.) < 1e-9);
174 }
175 
unaryMinusOperator()176 void TestCachingDms::unaryMinusOperator()
177 {
178     CachingDms d(56.3);
179     qDebug() << (-d).Degrees();
180     QVERIFY(qFuzzyCompare((-d).Degrees(), -56.3));
181     QVERIFY(qFuzzyCompare((-d).cos(), d.cos()));
182     QVERIFY(qFuzzyCompare((-d).sin(), -d.sin()));
183 }
184 
additionOperator()185 void TestCachingDms::additionOperator()
186 {
187     const double a = 123.7;
188     const double b = 89.5;
189     CachingDms d1(a);
190     CachingDms d2(b);
191     CachingDms ds       = d1 + d2;
192     const double sinapb = std::sin((a + b) * dms::DegToRad);
193     const double cosapb = std::cos((a + b) * dms::DegToRad);
194     QVERIFY(fabs(ds.sin() - sinapb) < 1e-9);
195     QVERIFY(fabs(ds.cos() - cosapb) < 1e-9);
196 
197     const double c = -34.7;
198     const double d = 233.6;
199     CachingDms d3(c);
200     CachingDms d4(d);
201     CachingDms ds2      = d3 + d4;
202     const double sincpd = std::sin((c + d) * dms::DegToRad);
203     const double coscpd = std::cos((c + d) * dms::DegToRad);
204     QVERIFY(fabs(ds2.sin() - sincpd) < 1e-9);
205     QVERIFY(fabs(ds2.cos() - coscpd) < 1e-9);
206 }
207 
subtractionOperator()208 void TestCachingDms::subtractionOperator()
209 {
210     const double a = 123.7;
211     const double b = 89.5;
212     CachingDms d1(a);
213     CachingDms d2(b);
214     CachingDms ds       = d1 - d2;
215     const double sinamb = std::sin((a - b) * dms::DegToRad);
216     const double cosamb = std::cos((a - b) * dms::DegToRad);
217     QVERIFY(fabs(ds.sin() - sinamb) < 1e-9);
218     QVERIFY(fabs(ds.cos() - cosamb) < 1e-9);
219 
220     const double c = -34.7;
221     const double d = 233.6;
222     CachingDms d3(c);
223     CachingDms d4(d);
224     CachingDms ds2      = d3 - d4;
225     const double sincmd = std::sin((c - d) * dms::DegToRad);
226     const double coscmd = std::cos((c - d) * dms::DegToRad);
227     QVERIFY(fabs(ds2.sin() - sincmd) < 1e-9);
228     QVERIFY(fabs(ds2.cos() - coscmd) < 1e-9);
229 }
230 
testFailsafeUseOfBaseClassPtr()231 void TestCachingDms::testFailsafeUseOfBaseClassPtr()
232 {
233     typedef union angle {
234         double x;
235         int64_t y;
236     } angle;
237     const int testCases = 5000;
238     std::srand(std::time(nullptr));
239     for (int k = 0; k < testCases; ++k)
240     {
241         angle a { 0 };
242         CachingDms _a;
243         dms __a;
244         a.y = std::rand();
245         _a.setD(a.x);
246         __a.setD(a.x);
247         dms *d;
248         if (std::rand() % 10 > 5)
249             d = &_a;
250         else
251             d = &__a;
252         angle b;
253         b.y = std::rand();
254         switch (std::rand() % 7)
255         {
256             case 0:
257                 d->setD(b.x);
258                 break;
259             case 1:
260                 d->setH(b.x / 15.);
261                 break;
262             case 2:
263             {
264                 dms x(b.x);
265                 d->setD(x.degree(), x.arcmin(), x.arcsec(), x.marcsec());
266                 break;
267             }
268             case 3:
269             {
270                 dms x(b.x);
271                 d->setFromString(x.toDMSString());
272                 break;
273             }
274             case 4:
275             {
276                 dms x(b.x);
277                 d->setFromString(x.toHMSString(), false);
278                 break;
279             }
280             case 5:
281             {
282                 dms x(b.x);
283                 dms y(0.0);
284                 *d = x + y;
285                 break;
286             }
287             case 6:
288             default:
289                 d->setRadians(b.x * dms::DegToRad);
290                 break;
291         }
292         QVERIFY(fabs(d->sin() - sin(b.x * dms::DegToRad)) < 1e-12);
293         QVERIFY(fabs(d->cos() - cos(b.x * dms::DegToRad)) < 1e-12);
294     }
295 }
296 
297 QTEST_GUILESS_MAIN(TestCachingDms)
298