swift
testaviation.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
7 
8 #include <QDateTime>
9 #include <QString>
10 #include <QTest>
11 
12 #include "test.h"
13 
17 #include "misc/aviation/altitude.h"
19 #include "misc/aviation/callsign.h"
22 #include "misc/aviation/heading.h"
26 #include "misc/aviation/waketurbulencecategory.h"
28 #include "misc/geo/latitude.h"
29 #include "misc/geo/longitude.h"
31 #include "misc/network/server.h"
32 #include "misc/network/user.h"
33 #include "misc/pq/angle.h"
34 #include "misc/pq/frequency.h"
35 #include "misc/pq/length.h"
37 #include "misc/pq/units.h"
38 
39 using namespace swift::misc::aviation;
40 using namespace swift::misc::physical_quantities;
41 using namespace swift::misc::network;
42 using namespace swift::misc::geo;
43 
44 namespace MiscTest
45 {
47  class CTestAviation : public QObject
48  {
49  Q_OBJECT
50 
51  private slots:
53  void headingBasics();
54 
56  void comAndNav();
57 
59  void sameAviationFrequency();
60 
62  void comFrequencyRounding();
63 
65  void transponder();
66 
68  void callsignWithContainers();
69 
71  void copyAndEqual();
72 
74  void altitude();
75 
77  void testGuessing();
78 
80  void testWakeTurbulenceCategories();
81  };
82 
83  void CTestAviation::headingBasics()
84  {
85  CHeading h1(180, CHeading::Magnetic, CAngleUnit::deg());
86  CHeading h2(180, CHeading::True, CAngleUnit::deg());
87  CHeading h3(181, CHeading::Magnetic, CAngleUnit::deg());
88  CAngle a1(200, CAngleUnit::deg());
89  CHeading h4;
90  h4 = h1;
91  QVERIFY2(h1 != h2, "Magnetic and true heading are not the same");
92  QVERIFY2(h1 < h3, "180deg are less than 181deg");
93  QVERIFY2(h3 > h1, "181deg are more than 181deg");
94  QVERIFY2(a1 > h3, "200deg are more than 181deg");
95  QVERIFY2(h4 == h1, "Values shall be equal");
96 
97  const CHeading copy(h1);
98  h1 -= copy;
99  QVERIFY2(h1.isZeroEpsilonConsidered(), "Expect zero value");
100  QCOMPARE(h1.value(), 0.0);
101 
102  // h4 = h1 + h2; does not work, because misleading
103  h2 += h2; // add just angle
104  QCOMPARE(h2.value(), 360.0);
105  }
106 
107  void CTestAviation::comAndNav()
108  {
111  QVERIFY2(c1 != c2, "COM system shall not be equal");
112  c1 = c2;
113  QVERIFY2(c1 == c2, "COM system shall be equal");
114  QVERIFY2(CNavSystem::isValidCivilNavigationFrequency(CFrequency(110.0, CFrequencyUnit::MHz())),
115  "Expect valid nav frequency");
116  QVERIFY2(!CNavSystem::isValidCivilNavigationFrequency(CFrequency(200.0, CFrequencyUnit::MHz())),
117  "Expect invalid nav frequency");
118  }
119 
120  void CTestAviation::sameAviationFrequency()
121  {
122  {
123  CFrequency freq1(129620000, CFrequencyUnit::Hz());
124  CFrequency freq2(129620000, CFrequencyUnit::Hz());
125  QVERIFY2(CComSystem::isSameFrequency(freq1, freq2), "Frequencies should be the same");
126  }
127 
128  {
129  CFrequency freq1(122.8, CFrequencyUnit::MHz());
130  CFrequency freq2(122.8, CFrequencyUnit::MHz());
131  QVERIFY2(CComSystem::isSameFrequency(freq1, freq2), "Frequencies should be the same");
132  }
133 
134  {
135  // Should be the same despite small rounding error in Hz range
136  CFrequency freq1(123450001, CFrequencyUnit::Hz());
137  CFrequency freq2(123450, CFrequencyUnit::kHz());
138  QVERIFY2(CComSystem::isSameFrequency(freq1, freq2), "Frequencies should be the same");
139  }
140 
141  {
142  // Ending with 20/70 is treated the same as 25/75 (correct value) as old radios only had 2 digits available
143  // after the decimal point
144  CFrequency freq1(118.325, CFrequencyUnit::MHz());
145  CFrequency freq2(118.320, CFrequencyUnit::MHz());
146  CFrequency freq3(132.770, CFrequencyUnit::MHz());
147  CFrequency freq4(132.775, CFrequencyUnit::MHz());
148  CFrequency freq5(132.765, CFrequencyUnit::MHz());
149  CFrequency freq6(132.780, CFrequencyUnit::MHz());
150 
151  QVERIFY2(CComSystem::isSameFrequency(freq1, freq2), "Frequencies should be the same");
152  QVERIFY2(CComSystem::isSameFrequency(freq3, freq4), "Frequencies should be the same");
153  QVERIFY2(!CComSystem::isSameFrequency(freq1, freq3), "Frequencies should not be the same");
154  QVERIFY2(!CComSystem::isSameFrequency(freq1, freq4), "Frequencies should not be the same");
155  QVERIFY2(!CComSystem::isSameFrequency(freq2, freq3), "Frequencies should not be the same");
156  QVERIFY2(!CComSystem::isSameFrequency(freq2, freq4), "Frequencies should not be the same");
157  QVERIFY2(!CComSystem::isSameFrequency(freq3, freq5), "Frequencies should not be the same");
158  QVERIFY2(!CComSystem::isSameFrequency(freq3, freq6), "Frequencies should not be the same");
159  QVERIFY2(!CComSystem::isSameFrequency(freq4, freq5), "Frequencies should not be the same");
160  QVERIFY2(!CComSystem::isSameFrequency(freq4, freq6), "Frequencies should not be the same");
161  }
162 
163  {
164  CFrequency freq1(129620000, CFrequencyUnit::Hz());
165  CFrequency freq2(132025000, CFrequencyUnit::Hz());
166  QVERIFY2(!CComSystem::isSameFrequency(freq1, freq2), "Frequencies should not be the same");
167  }
168 
169  // 8.33 kHz frequencies
170  {
171  CFrequency freq1(118.305, CFrequencyUnit::MHz());
172  CFrequency freq2(118305, CFrequencyUnit::kHz());
173  QVERIFY2(CComSystem::isSameFrequency(freq1, freq2), "Frequencies should be the same");
174  }
175 
176  {
177  CFrequency freq1(118.310, CFrequencyUnit::MHz());
178  CFrequency freq2(118305, CFrequencyUnit::kHz());
179  QVERIFY2(!CComSystem::isSameFrequency(freq1, freq2), "Frequencies should not be the same");
180  }
181 
182  {
183  CFrequency freq1(135.660, CFrequencyUnit::MHz());
184  CFrequency freq2(135665, CFrequencyUnit::kHz());
185  QVERIFY2(!CComSystem::isSameFrequency(freq1, freq2), "Frequencies should not be the same");
186  }
187  }
188 
189  void CTestAviation::comFrequencyRounding()
190  {
191  const CFrequency f1 = CFrequency(122.8, CFrequencyUnit::MHz());
192  const CFrequency f2 = CFrequency(122.795, CFrequencyUnit::MHz());
193  const CFrequency f3 = CFrequency(122.805, CFrequencyUnit::MHz());
194  const CFrequency f4 = CFrequency(122.225, CFrequencyUnit::MHz());
195  const CFrequency f5 = CFrequency(122.220, CFrequencyUnit::MHz());
196 
197  QVERIFY2(f1 == f1, "Ups, how can this fail");
198  QVERIFY2(f1 != f2, "Ups, how can this fail");
199  QVERIFY2(f1 != f3, "Ups, how can this fail");
200  QVERIFY2(f4 != f5, "Ups, how can this fail");
201 
202  CFrequency up(f2);
204  QVERIFY2(up == f1, "Expect rounding up");
205 
206  CFrequency down(f3);
208  QVERIFY2(down == f1, "Expect rounding up");
209 
210  CFrequency same(f3);
212  QVERIFY2(same != f1, "Expect no rounding");
213  QVERIFY2(same == f3, "Expect no rounding");
214 
215  CFrequency up2(f5);
217  QVERIFY2(up2 == f4, "Expect rounding up");
218  }
219 
220  void CTestAviation::transponder()
221  {
223  CTransponder t2 = t1;
224  QVERIFY2(t1 == t2, "Transponders shall be equal");
225  t2.setTransponderMode(CTransponder::ModeC);
226  QVERIFY2(t1 != t2, "Transponders shall not be equal");
228  QVERIFY2(!tv.validValues(), "No valid transponder");
230  QVERIFY2(!tv.validValues(), "No valid transponder");
232  QVERIFY2(!tv.validValues(), "No valid transponder");
234  QVERIFY2(tv.validValues(), "No valid transponder");
235  tv = CTransponder("schnitzel", CTransponder::StateStandby);
236  QVERIFY2(!tv.validValues(), "No valid transponder");
237  }
238 
239  void CTestAviation::callsignWithContainers()
240  {
241  const CCallsign cs1("EDDm_twr");
242  const CCallsign cs2("eddm_TWR");
243  const CCallsign cs3("EDDm_app", "München Radar");
244  QVERIFY2(cs1 == cs2, "Callsigns shall be equal");
245  QVERIFY2(cs1 != cs3, "Callsigns shall not be equal");
246 
247  const CCallsign pilot("DLH123");
248  const CCallsign copilot1("DLH123A");
249  const CCallsign copilot2("DLH1233");
250  const CCallsign copilot3("DLH12");
251  QVERIFY(copilot1.isMaybeCopilotCallsign(pilot));
252  QVERIFY(!pilot.isMaybeCopilotCallsign(pilot));
253  QVERIFY(!copilot2.isMaybeCopilotCallsign(pilot));
254  QVERIFY(!copilot3.isMaybeCopilotCallsign(pilot));
255 
256  QString flightnumber;
257  QString identifier;
258 
259  QString prefix = pilot.getAirlinePrefix(flightnumber, identifier);
260  QVERIFY(prefix == "DLH");
261  QVERIFY(flightnumber == "123");
262  QVERIFY(flightnumber == identifier);
263  prefix = copilot1.getAirlinePrefix(flightnumber, identifier);
264  QVERIFY(prefix == "DLH");
265  QVERIFY(flightnumber == "123");
266  QVERIFY(flightnumber != identifier);
267  prefix = copilot3.getAirlinePrefix(flightnumber);
268  QVERIFY(prefix == "DLH");
269  QVERIFY(flightnumber == "12");
270 
271  const CCallsign pilotX1("DLHFOO");
272  prefix = pilotX1.getAirlinePrefix(flightnumber);
273  QVERIFY(prefix.isEmpty()); // no prefix
274  QVERIFY(flightnumber.isEmpty());
275 
276  const CCallsign pilotX2("DLH1WP");
277  prefix = pilotX2.getAirlinePrefix(flightnumber, identifier);
278  QVERIFY(prefix == "DLH"); // no prefix
279  QVERIFY(flightnumber == "1");
280  QVERIFY(identifier == "1WP");
281 
282  CCallsignSet set;
283  set.push_back(cs1);
284  QVERIFY2(set.size() == 1, "List shall be 1");
285  QVERIFY2(set.contains(cs1), "Callsign is in list");
286  QVERIFY2(set.contains(cs2), "Callsign is in list");
287  set.remove(cs1);
288  QVERIFY2(cs1 == cs1, "Callsign is the same, shall be equal");
289  QVERIFY2(set.size() == 0, "List shall be 0 after removal");
290  set.push_back(cs1);
291  if (!set.contains(cs2)) set.push_back(cs2);
292  QVERIFY2(set.size() == 1, "Duplicates shall not be added");
293  set.push_back(cs3);
294  QVERIFY2(set.size() == 2, "2 different callsigns");
295  set.remove(cs1);
296  QVERIFY2(set.size() == 1, "Only one should be left in list");
297  set.removeIf(&CCallsign::getTelephonyDesignator, "München Radar");
298  QVERIFY2(set.size() == 0, "Last should be gone");
299  }
300 
301  void CTestAviation::copyAndEqual()
302  {
303  const CFrequency f1(123.45, CFrequencyUnit::MHz());
304  const CFrequency f2(f1);
305  QVERIFY2(f1 == f2, "frequencies shall be equal");
306 
307  const CCallsign c1("EABCD");
308  const CCallsign c2(c1);
309  QVERIFY2(c1 == c2, "callsigns shall be equal");
310 
311  const CInformationMessage im1(CInformationMessage::METAR, "I am a metar");
312  const CInformationMessage im2(im1);
313  QVERIFY2(im1 == im2, "information shall be equal");
314 
315  const CUser user1("112233dd", "Joe", "", "secret");
316  const CUser user2(user1);
317  QVERIFY2(user1 == user2, "information shall be equal");
318 
319  const CServer server1 =
320  CServer("Testserver", "Client project testserver", "localhost", 6809, CUser("111111", "My Name", "", "123"),
321  CFsdSetup(), CEcosystem(CEcosystem::swiftTest()), CServer::FSDServerVatsim);
322  const CServer server2(server1);
323  QVERIFY2(server1 == server2, "server shall be equal");
324 
325  const CAircraftSituation situation1(CCoordinateGeodetic(CLatitude::fromWgs84("N 049° 18' 17"),
326  CLongitude::fromWgs84("E 008° 27' 05"),
327  CAltitude(312, CLengthUnit::ft())));
328  const CAircraftSituation situation2(situation1);
329  QVERIFY2(situation1 == situation2, "situations shall be equal");
330 
331  const CAircraftIcaoCode aircraftIcao1("C172", "L1P");
332  const CAircraftIcaoCode aircraftIcao2(aircraftIcao1);
333  QVERIFY2(aircraftIcao1 == aircraftIcao2, "aircraft ICAOs shall be equal");
334 
335  const CAirlineIcaoCode airlineIcao1("GA");
336  const CAirlineIcaoCode airlineIcao2(airlineIcao1);
337  QVERIFY2(airlineIcao1 == airlineIcao2, "airline ICAOs shall be equal");
338 
339  const CCallsign call1("EDDS_N_APP", CCallsign::Atc);
340  const CCallsign call2("edds_n_app", CCallsign::Atc);
341  QVERIFY2(call1 == call2, "Callsigns shall be equal");
342 
343  const CAtcStation atc1(c1, user1, f1, situation1.getPosition(), CLength(), false, QDateTime(),
344  CInformationMessage(CInformationMessage::ATIS, "foo"));
345  const CAtcStation atc2(c1, user1, f1, situation1.getPosition(), CLength(), false, QDateTime(),
346  CInformationMessage(CInformationMessage::ATIS, "foo"));
347  const CAtcStation atc3(c1, user1, f1, situation1.getPosition(), CLength(), false, QDateTime(),
348  CInformationMessage(CInformationMessage::ATIS, "bar"));
349  QVERIFY2(atc1 == atc2, "ATC stations shall be equal");
350  QVERIFY2(atc1 != atc3, "ATC stations shall not be equal");
351  }
352 
353  void CTestAviation::altitude()
354  {
355  CAltitude altitude1(448, CAltitude::MeanSeaLevel, CLengthUnit::ft());
356  CPressure seaLevelPressure1(1025, CPressureUnit::mbar());
357  CAltitude pressureAltitude1 = altitude1.toPressureAltitude(seaLevelPressure1);
358  QCOMPARE(pressureAltitude1.value(CLengthUnit::ft()), 95.5);
359 
360  CAltitude altitude2(500, CAltitude::MeanSeaLevel, CLengthUnit::m());
361  CPressure seaLevelPressure2(29.56, CPressureUnit::inHg());
362  CAltitude pressureAltitude2 = altitude2.toPressureAltitude(seaLevelPressure2);
363  QCOMPARE(qRound(pressureAltitude2.value(CLengthUnit::m())), 612);
364 
365  CLength offset(10, CLengthUnit::m());
366  altitude2 += offset;
367  QCOMPARE(qRound(altitude2.value(CLengthUnit::m())), 510);
368  }
369 
370  void CTestAviation::testGuessing()
371  {
372  const CAircraftIcaoCode icao172("C172", "L1P");
373  const CAircraftIcaoCode icaoB737("B737", "L2J");
374  const CAircraftIcaoCode icaoB747("B747", "L4J");
375 
376  CSpeed s172, sB737, sB747;
377  s172 = sB737 = sB747 = CSpeed::null();
378  CLength cg172, cgB737, cgB747;
379  cg172 = cgB737 = cgB747 = CLength::null();
380  icao172.guessModelParameters(cg172, s172);
381  icaoB737.guessModelParameters(cgB737, sB737);
382  icaoB747.guessModelParameters(cgB747, sB747);
383 
384  QVERIFY(cg172 < cgB737);
385  QVERIFY(cgB737 < cgB747);
386 
387  QVERIFY(s172 < sB747);
388  QVERIFY(sB737 < sB747);
389  }
390 
391  void CTestAviation::testWakeTurbulenceCategories()
392  {
393  const CWakeTurbulenceCategory catLight1('L');
394  const CWakeTurbulenceCategory catLight2('l');
396 
397  const CWakeTurbulenceCategory catMedium1('M');
398  const CWakeTurbulenceCategory catMedium2('m');
400 
401  const CWakeTurbulenceCategory catHeavy1('H');
402  const CWakeTurbulenceCategory catHeavy2('h');
404 
405  const CWakeTurbulenceCategory catSuper1('J');
406  const CWakeTurbulenceCategory catSuper2('j');
408 
409  const CWakeTurbulenceCategory catUnknown1('-');
410  const CWakeTurbulenceCategory catUnknown2('A');
411  const CWakeTurbulenceCategory catUnknown3('x');
413 
414  QVERIFY(catLight1.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::LIGHT));
415  QVERIFY(catLight2.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::LIGHT));
416  QVERIFY(catLight3.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::LIGHT));
417  QCOMPARE(catLight1.toQString(), "L");
418 
419  QVERIFY(catMedium1.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::MEDIUM));
420  QVERIFY(catMedium2.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::MEDIUM));
421  QVERIFY(catMedium3.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::MEDIUM));
422  QCOMPARE(catMedium1.toQString(), "M");
423 
424  QVERIFY(catHeavy1.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::HEAVY));
425  QVERIFY(catHeavy2.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::HEAVY));
426  QVERIFY(catHeavy3.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::HEAVY));
427  QCOMPARE(catHeavy1.toQString(), "H");
428 
429  QVERIFY(catSuper1.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::SUPER));
430  QVERIFY(catSuper2.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::SUPER));
431  QVERIFY(catSuper3.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::SUPER));
432  QCOMPARE(catSuper1.toQString(), "J");
433 
434  QVERIFY(catUnknown1.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::UNKNOWN));
435  QVERIFY(catUnknown1.isUnknown());
436  QVERIFY(catUnknown2.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::UNKNOWN));
437  QVERIFY(catUnknown2.isUnknown());
438  QVERIFY(catUnknown3.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::UNKNOWN));
439  QVERIFY(catUnknown3.isUnknown());
440  QVERIFY(catUnknown4.isCategory(swift::misc::aviation::CWakeTurbulenceCategory::UNKNOWN));
441  QVERIFY(catUnknown4.isUnknown());
442  QCOMPARE(catUnknown1.toQString(), "-");
443  }
444 
445 } // namespace MiscTest
446 
449 
450 #include "testaviation.moc"
451 
Aviation classes basic tests.
size_type size() const
Returns number of elements in the collection.
Definition: collection.h:185
void remove(const T &object)
Efficient remove using the find and erase of the implementation container. Typically O(log n).
Definition: collection.h:307
int removeIf(Predicate p)
Remove elements for which a given predicate returns true.
Definition: collection.h:321
iterator push_back(const T &value)
Synonym for insert.
Definition: collection.h:238
bool contains(const T &object) const
Return true if there is an element equal to given object. Uses the most efficient implementation avai...
Definition: range.h:109
Value object for ICAO classification.
Value object encapsulating information of an aircraft's situation.
Value object for ICAO classification.
Altitude as used in aviation, can be AGL or MSL altitude.
Definition: altitude.h:52
CAltitude toPressureAltitude(const physical_quantities::CPressure &seaLevelPressure) const
Returns the altitude converted to pressure altitude. Requires the current barometric pressure at MSL.
Definition: altitude.cpp:131
Value object encapsulating information about an ATC station.
Definition: atcstation.h:38
Value object encapsulating information of a callsign.
Definition: callsign.h:30
const QString & getTelephonyDesignator() const
Get callsign telephony designator (how callsign is pronounced)
Definition: callsign.h:108
Value object for a set of callsigns.
Definition: callsignset.h:26
COM system (aka "radio")
Definition: comsystem.h:37
static void roundToChannelSpacing(physical_quantities::CFrequency &frequency, ChannelSpacing channelSpacing)
Round to channel spacing, set MHz as unit.
Definition: comsystem.cpp:144
static CComSystem getCom1System(double activeFrequencyMHz, double standbyFrequencyMHz=-1)
COM1 unit.
Definition: comsystem.cpp:64
static bool isSameFrequency(const physical_quantities::CFrequency &freq1, const physical_quantities::CFrequency &freq2)
Compare frequencies under consideration that on VATSIM frequencies .x20/.x25 and ....
Definition: comsystem.cpp:181
static CComSystem getCom2System(double activeFrequencyMHz, double standbyFrequencyMHz=-1)
COM2 unit.
Definition: comsystem.cpp:79
Heading as used in aviation, can be true or magnetic heading.
Definition: heading.h:41
@ Magnetic
magnetic north
Definition: heading.h:56
Value object encapsulating information message (ATIS, METAR, TAF)
static bool isValidCivilNavigationFrequency(const swift::misc::physical_quantities::CFrequency &f)
Valid civil aviation frequency?
Definition: navsystem.h:54
static CTransponder getStandardTransponder(qint32 transponderCode, TransponderMode mode)
Transponder unit.
bool setTransponderMode(TransponderMode mode)
Set transponder mode.
Definition: transponder.cpp:97
bool validValues() const
Are set values valid?
Definition: transponder.cpp:49
@ StateStandby
not a real mode, more a state
Definition: transponder.h:33
@ UNKNOWN
required when converting from FAA equipment codes and for some database entries where the correct WTC...
Ecosystem of server belonging together.
Definition: ecosystem.h:21
Value object for a FSD setup.
Definition: fsdsetup.h:24
Value object encapsulating information of a server.
Definition: server.h:28
Value object encapsulating information of a user.
Definition: user.h:28
Physical unit angle (radians, degrees)
Definition: angle.h:23
Physical unit length (length)
Definition: length.h:18
double value(MU unit) const
Value in given unit.
SWIFTTEST_APPLESS_MAIN(MiscTest::CTestAviation)
main