12 #include <QCoreApplication>
17 #include <QJsonObject>
20 #include <QMetaObject>
21 #include <QRegularExpression>
46 using namespace swift::misc::aviation;
47 using namespace swift::misc::simulation;
65 void localOnlyWithThreads();
90 void ps_valueChanged();
102 void CTestValueCache::insertAndGet()
115 cache.insertValues({ testData, QDateTime::currentMSecsSinceEpoch() });
116 QVERIFY(cache.getAllValues() == testData);
117 cache.insertValues({ testData2, QDateTime::currentMSecsSinceEpoch() });
118 QVERIFY(cache.getAllValues() == testDataCombined);
122 void waitForQueueOf(QObject *
object)
124 if (object->thread() != QThread::currentThread())
126 std::promise<void> promise;
128 promise.get_future().wait();
132 template <
typename F>
133 void singleShotAndWait(QObject *
object, F task)
135 if (object->thread() == QThread::currentThread()) { task(); }
139 waitForQueueOf(
object);
143 void testCommon(CValueCacheUser &user1, CValueCacheUser &user2)
145 user1.m_value1.set(42);
146 QVERIFY(user2.slotFired());
147 QVERIFY(!user1.slotFired());
148 singleShotAndWait(&user2, [&] { QVERIFY(user2.m_value1.get() == 42); });
149 QVERIFY(user1.m_value1.get() == 42);
151 user1.m_value2.set(42);
153 auto status = user1.m_value2.set(-1337);
154 QVERIFY(status.isFailure());
155 QVERIFY(!user1.slotFired());
156 QVERIFY(!user2.slotFired());
157 singleShotAndWait(&user2, [&] { QVERIFY(user2.m_value2.get() == 42); });
158 QVERIFY(user1.m_value2.get() == 42);
162 void CTestValueCache::localOnly()
165 for (
int i = 0; i < 2; ++i) { QTest::ignoreMessage(QtDebugMsg, QRegularExpression(
"Empty cache value")); }
166 CValueCacheUser user1(&cache);
167 CValueCacheUser user2(&cache);
168 testCommon(user1, user2);
171 void CTestValueCache::localOnlyWithThreads()
174 for (
int i = 0; i < 2; ++i) { QTest::ignoreMessage(QtDebugMsg, QRegularExpression(
"Empty cache value")); }
175 CValueCacheUser user1(&cache);
176 CValueCacheUser user2(&cache);
178 user2.moveToThread(&thread);
180 testCommon(user1, user2);
183 void CTestValueCache::distributed()
187 auto json = otherProcess.
toJson();
188 json.insert(
"processId", otherProcess.
getProcessId() + 1);
194 QMetaObject::invokeMethod(&thisCache,
195 [=, &thisCache] { thisCache.changeValuesFromRemote(values, thisProcess); });
196 QMetaObject::invokeMethod(&otherCache,
197 [=, &otherCache] { otherCache.changeValuesFromRemote(values, otherProcess); });
200 QMetaObject::invokeMethod(&thisCache,
201 [=, &thisCache] { thisCache.changeValuesFromRemote(values, otherProcess); });
202 QMetaObject::invokeMethod(&otherCache,
203 [=, &otherCache] { otherCache.changeValuesFromRemote(values, thisProcess); });
206 for (
int i = 0; i < 4; ++i) { QTest::ignoreMessage(QtDebugMsg, QRegularExpression(
"Empty cache value")); }
207 CValueCacheUser thisUser(&thisCache);
208 CValueCacheUser otherUser(&otherCache);
211 otherCache.moveToThread(&thread);
212 otherUser.moveToThread(&thread);
215 singleShotAndWait(&otherUser, [&] { otherUser.m_value1.set(99); });
216 thisUser.m_value1.set(100);
217 QCoreApplication::processEvents();
218 waitForQueueOf(&otherUser);
219 QVERIFY(thisUser.slotFired() != otherUser.slotFired());
220 auto thisValue = thisUser.m_value1.get();
221 singleShotAndWait(&otherUser, [&] { QVERIFY(thisValue == otherUser.m_value1.get()); });
224 void CTestValueCache::batched()
227 for (
int i = 0; i < 2; ++i) { QTest::ignoreMessage(QtDebugMsg, QRegularExpression(
"Empty cache value")); }
228 CValueCacheUser user1(&cache);
229 CValueCacheUser user2(&cache);
232 auto batch = cache.batchChanges(&user1);
233 user1.m_value1.set(42);
234 user1.m_value2.set(42);
236 QVERIFY(!user1.slotFired());
237 QVERIFY(user2.slotFired());
238 singleShotAndWait(&user2, [&] {
239 QVERIFY(user2.m_value1.get() == 42);
240 QVERIFY(user2.m_value2.get() == 42);
244 void CTestValueCache::json()
254 cache.loadFromJson(testJson);
255 QVERIFY(cache.getAllValues() == testData);
256 QVERIFY(cache.saveToJson() == testJson);
259 void CTestValueCache::saveAndLoad()
269 cache.insertValues({ testData, QDateTime::currentMSecsSinceEpoch() });
271 QDir dir(QDir::currentPath() +
"/testcache");
272 if (dir.exists()) { dir.removeRecursively(); }
274 auto status = cache.saveToFiles(dir.absolutePath());
275 QVERIFY(status.isSuccess());
277 auto files = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot, QDir::Name);
278 QCOMPARE(files.size(), 2);
279 QCOMPARE(files[0].fileName(), QString(
"namespace1.json"));
280 QCOMPARE(files[1].fileName(), QString(
"namespace2.json"));
283 status = cache2.loadFromFiles(dir.absolutePath());
284 QVERIFY(status.isSuccess());
285 const CVariantMap test2Values = cache2.getAllValues();
286 QCOMPARE(test2Values, testData);
290 bool validator(
int value, QString &) {
return value >= 0 && value <= 100; }
293 : m_value1(cache,
"value1",
"",
validator, 0, this), m_value2(cache,
"value2",
"",
validator, 0, this)
303 auto status =
m_slotFired.get_future().wait_for(std::chrono::milliseconds(250));
307 case std::future_status::ready:
return true;
308 case std::future_status::timeout:
return false;
309 case std::future_status::deferred:
310 default: QTEST_ASSERT(
false);
319 #include "testvaluecache.moc"
Unit tests for value cache system.
Simple class which uses CCached, for testing.
std::promise< void > m_slotFired
Flag marking whether the slot was called.
bool slotFired()
Detect whether the slot was called, for verification.
swift::misc::CCached< int > m_value1
First cached value.
swift::misc::CCached< int > m_value2
Second cached value.
void ps_valueChanged()
Slot to be called when a cached value changes.
CValueCacheUser(swift::misc::CValueCache *cache)
Constructor.
void setNotifySlot(F slot)
Set a callback to be called when the value is changed by another source.
Value object encapsulating information identifying a component of a modular distributed swift process...
qint64 getProcessId() const
Get process id.
Just a subclass of QThread whose destructor waits for the thread to finish.
Manages a map of { QString, CVariant } pairs, which can be distributed among multiple processes.
void valuesChangedByLocal(const swift::misc::CValueCachePacket &values)
Emitted when values in the cache are changed by an object in this very process. The interprocess comm...
Value class used for signalling changed values in the cache.
static CVariant from(T &&value)
Synonym for fromValue().
QJsonObject toJson() const
Cast to JSON object.
Map of { QString, CVariant } pairs.
Value object encapsulating information about an ATC station.
Value object for a list of ATC stations.
Comprehensive information of an aircraft.
Value object encapsulating a list of aircraft.
Free functions in swift::misc.
void registerMetadata()
Register all relevant metadata in Misc.
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...
SWIFTTEST_MAIN(MiscTest::CTestValueCache)
main
bool validator(int value, QString &)
Is value between 0 - 100?