File indexing completed on 2024-04-28 11:25:54
0001 /* 0002 SPDX-FileCopyrightText: 2021 Valentin Boettcher <hiro at protagon.space; @hiro98:tchncs.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include <QTest> 0008 #include <QtConcurrent/QtConcurrentRun> 0009 #include <QTemporaryDir> 0010 #include <QTemporaryFile> 0011 #include <qtestcase.h> 0012 #include "catalogsdb.h" 0013 #include "skymesh.h" 0014 0015 using namespace CatalogsDB; 0016 class TestCatalogsDB_DBManager : public QObject 0017 { 0018 Q_OBJECT 0019 public: 0020 TestCatalogsDB_DBManager() : m_manager{ getTestSqliteFile() } {} 0021 0022 private: 0023 const QString db_file_og = QFINDTESTDATA("data/test.sqlite"); 0024 DBManager m_manager; 0025 CatalogObject some_object() { return m_manager.get_objects(99, 1).front(); } 0026 QString getTestSqliteFile() 0027 { 0028 const QString db_file = "test.sqlite"; 0029 QFile::remove(db_file); 0030 QFile::copy(db_file_og, db_file); 0031 return db_file; 0032 } 0033 0034 private slots: 0035 void init() 0036 { 0037 // A fresh manager for each test. 0038 m_manager = DBManager{ getTestSqliteFile() }; 0039 }; 0040 0041 void user_catalog_created() 0042 { 0043 QTemporaryFile tmp; 0044 m_manager = DBManager{ tmp.fileName() }; 0045 QCOMPARE(m_manager.get_catalog(0).second.id, 0); 0046 } 0047 0048 void getting_catalogs() 0049 { 0050 // first without disabled 0051 const auto &cats = m_manager.get_catalogs(); 0052 for (const auto &cat : cats) 0053 { 0054 // the catalogs should be the same 0055 QCOMPARE(m_manager.get_catalog(cat.id).second.id, cat.id); 0056 // and they should exist 0057 QVERIFY(m_manager.catalog_exists(cat.id)); 0058 QVERIFY(cat.enabled); 0059 } 0060 0061 // and then with disabled 0062 const auto &cats_d = m_manager.get_catalogs(true); 0063 for (const auto &cat : cats_d) 0064 { 0065 // the catalogs should be the same 0066 QCOMPARE(m_manager.get_catalog(cat.id).second.id, cat.id); 0067 // and they should exist 0068 QVERIFY(m_manager.catalog_exists(cat.id)); 0069 } 0070 } 0071 0072 void getting_objects_in_trixel() 0073 { 0074 const int num_trixels = SkyMesh::Create(m_manager.htmesh_level())->size(); 0075 int num_obj = 0; 0076 0077 QBENCHMARK 0078 { 0079 for (int trixel = 0; trixel < num_trixels; trixel++) 0080 { 0081 num_obj += m_manager.get_objects_in_trixel(trixel).size(); 0082 } 0083 } 0084 0085 QVERIFY(num_obj > 0); 0086 } 0087 0088 void find_by_name() 0089 { 0090 const auto &obj = some_object(); 0091 const auto &objs = m_manager.find_objects_by_name(obj.name(), 1); 0092 QCOMPARE(objs.size(), 1); 0093 QCOMPARE(obj.name(), objs.front().name()); 0094 } 0095 0096 void get_by_id() 0097 { 0098 const auto &obj = some_object(); 0099 const auto &fetched = m_manager.get_object(obj.getObjectId()); 0100 0101 QVERIFY(fetched.first); 0102 QCOMPARE(fetched.second, obj); 0103 0104 const auto &fetched_in_cat = 0105 m_manager.get_object(obj.getObjectId(), obj.getCatalog().id); 0106 0107 QVERIFY(fetched_in_cat.first); 0108 QCOMPARE(fetched_in_cat.second, obj); 0109 } 0110 0111 void get_objects_by_maglim() 0112 { 0113 const auto &objs = m_manager.get_objects(1, 10); 0114 QVERIFY(objs.size() <= 10); 0115 0116 for (const auto &obj : objs) 0117 { 0118 QVERIFY(obj.mag() <= 1); 0119 } 0120 } 0121 0122 void get_objects_by_type() 0123 { 0124 const auto &objs = m_manager.get_objects(SkyObject::SUPERNOVA_REMNANT, 1, 10); 0125 QVERIFY(objs.size() <= 10); 0126 0127 for (const auto &obj : objs) 0128 { 0129 QVERIFY(obj.mag() <= 1); 0130 QCOMPARE(obj.type(), SkyObject::SUPERNOVA_REMNANT); 0131 } 0132 } 0133 0134 void get_objects_by_type_in_catalog() 0135 { 0136 for (const auto &cat : m_manager.get_catalogs(true)) 0137 { 0138 const auto &cat_id = cat.id; 0139 const auto &objs = m_manager.get_objects_in_catalog( 0140 SkyObject::SUPERNOVA_REMNANT, cat_id, 1, 10); 0141 QVERIFY(objs.size() <= 10); 0142 0143 for (const auto &obj : objs) 0144 { 0145 QVERIFY(obj.mag() <= 1); 0146 QCOMPARE(obj.type(), SkyObject::SUPERNOVA_REMNANT); 0147 QCOMPARE(obj.getCatalog().id, cat_id); 0148 } 0149 } 0150 } 0151 0152 void enable_disable_catalogs() 0153 { 0154 for (const auto &cat : m_manager.get_catalogs(true)) 0155 { 0156 for (const auto enable : { true, false }) 0157 { 0158 const auto &success = m_manager.set_catalog_enabled(cat.id, enable); 0159 QVERIFY(success.first); 0160 QCOMPARE(m_manager.get_catalog(cat.id).second.enabled, enable); 0161 } 0162 } 0163 0164 const auto &objs = m_manager.get_objects(); 0165 QCOMPARE(objs.size(), 0); 0166 } 0167 0168 void remove_catalog() 0169 { 0170 for (const auto &cat : m_manager.get_catalogs(true)) 0171 { 0172 const auto size = m_manager.get_catalogs(true).size(); 0173 const auto &success = m_manager.remove_catalog(cat.id); 0174 if (cat.id == 0) // user catalog cannot be deleted 0175 { 0176 QVERIFY(!success.first); 0177 continue; 0178 } 0179 0180 QVERIFY(success.first); 0181 QCOMPARE(m_manager.get_catalogs(true).size(), size - 1); 0182 } 0183 } 0184 0185 void register_dump_and_read_catalog() 0186 { 0187 QTemporaryDir dir; 0188 QVERIFY(dir.isValid()); 0189 const auto &path = QString("%1/%2").arg(dir.path()).arg("tmp.sql"); 0190 0191 const auto &names = { "a", "b", "c" }; 0192 const int id = m_manager.find_suitable_catalog_id(); 0193 0194 const auto &now = QDateTime::currentDateTime(); 0195 auto success = 0196 m_manager.register_catalog(id, "test", true, true, 1, "me", "test suite", 0197 "test catalog", 2, "green", "gpl", "me", now); 0198 QVERIFY(success.first); 0199 0200 for (const auto &name : names) 0201 m_manager.add_object(id, SkyObject::STAR, dms{ 0 }, dms{ 0 }, name); 0202 0203 const auto &objects = m_manager.get_objects_in_catalog(SkyObject::STAR, id); 0204 0205 success = m_manager.dump_catalog(id, path); 0206 QVERIFY2(success.first, "Dumping catalogs."); 0207 0208 const auto cat_meta = CatalogsDB::read_catalog_meta_from_file(path); 0209 0210 QVERIFY2(cat_meta.first, "Read dumped catalog meta data."); 0211 QCOMPARE(cat_meta.second.id, id); 0212 QCOMPARE(cat_meta.second.name, "test"); 0213 QCOMPARE(cat_meta.second.precedence, 1); 0214 QCOMPARE(cat_meta.second.author, "me"); 0215 QCOMPARE(cat_meta.second.mut, true); 0216 QCOMPARE(cat_meta.second.enabled, true); 0217 QCOMPARE(cat_meta.second.source, "test suite"); 0218 QCOMPARE(cat_meta.second.description, "test catalog"); 0219 QCOMPARE(cat_meta.second.version, 2); 0220 QCOMPARE(cat_meta.second.color, "green"); 0221 QCOMPARE(cat_meta.second.license, "gpl"); 0222 QCOMPARE(cat_meta.second.maintainer, "me"); 0223 QCOMPARE(cat_meta.second.timestamp, now); 0224 0225 success = m_manager.import_catalog(path); 0226 QVERIFY2(!success.first, "Not overwriting an existing catalog."); 0227 0228 success = m_manager.import_catalog(path, true); 0229 QVERIFY2(success.first, "Importing and overwriting."); // import and overwrite 0230 0231 success = m_manager.remove_catalog(id); // remove and import fresh 0232 QVERIFY(!m_manager.get_catalog(id).first); 0233 0234 success = m_manager.import_catalog(path); 0235 QVERIFY2(success.first, "Importing fresh."); 0236 0237 const auto &new_objects = m_manager.get_objects_in_catalog(SkyObject::STAR, id); 0238 for (const auto &object : objects) 0239 { 0240 QVERIFY2(std::find(new_objects.cbegin(), new_objects.cend(), object) != 0241 new_objects.cend(), 0242 "Object found in reimported catalog."); 0243 } 0244 } 0245 0246 void edit_catalog() 0247 { 0248 const Catalog cat = { 0249 0, "New User", 0, "test", "toast", "toaster", false, false 0250 }; 0251 0252 auto success = m_manager.update_catalog_meta(cat); 0253 QVERIFY2(success.first, "Changing meta works."); 0254 QCOMPARE(m_manager.get_catalog(0).second.name, "New User"); 0255 QCOMPARE(m_manager.get_catalog(0).second.author, "test"); 0256 QCOMPARE(m_manager.get_catalog(0).second.source, "toast"); 0257 QCOMPARE(m_manager.get_catalog(0).second.description, "toaster"); 0258 QCOMPARE(m_manager.get_catalog(0).second.mut, true); // did not change 0259 0260 success = m_manager.update_catalog_meta({ -1, "bla" }); 0261 QVERIFY2(!success.first, "Changing meta of nonexisting catalog doesn't work."); 0262 } 0263 0264 void register_from_catalog_objetct() 0265 { 0266 const Catalog cat{ m_manager.find_suitable_catalog_id(), 0267 "test", 0268 1, 0269 "tester", 0270 "test catalog", 0271 "testing catalog", 0272 true, 0273 false, 0274 100 }; 0275 0276 auto success = m_manager.register_catalog(cat); 0277 QVERIFY2(success.first, "Registering a catalog worked."); 0278 0279 const auto &success_fetch = m_manager.get_catalog(cat.id); 0280 QVERIFY2(success_fetch.first, "Inserted catalog found."); 0281 0282 const auto &cat_new = success_fetch.second; 0283 QCOMPARE(cat_new.id, cat.id); 0284 QCOMPARE(cat_new.name, cat.name); 0285 QCOMPARE(cat_new.precedence, cat.precedence); 0286 QCOMPARE(cat_new.author, cat.author); 0287 QCOMPARE(cat_new.source, cat.source); 0288 QCOMPARE(cat_new.description, cat.description); 0289 QCOMPARE(cat_new.enabled, cat.enabled); 0290 QCOMPARE(cat_new.version, cat.version); 0291 } 0292 0293 void add_object_and_copy() 0294 { 0295 const Catalog cat{ m_manager.find_suitable_catalog_id(), 0296 "test", 0297 1, 0298 "tester", 0299 "test catalog", 0300 "testing catalog", 0301 true, 0302 false, 0303 100 }; 0304 0305 auto success = m_manager.register_catalog(cat); 0306 QVERIFY2(success.first, "Registering a catalog worked."); 0307 0308 auto success_add = 0309 m_manager.add_object(cat.id, SkyObject::STAR, dms{ 1 }, dms{ 0 }, "test", -1, 0310 "long test", "NGC 100", 10, 11, 111, 0); 0311 QVERIFY2(success_add.first, "Inserting an object worked."); 0312 0313 const auto obj = 0314 m_manager.get_objects_in_catalog(SkyObject::STAR, cat.id, 99, 1).front(); 0315 0316 QCOMPARE(obj.type(), SkyObject::STAR); 0317 QCOMPARE(obj.ra0(), dms{ 1 }); 0318 QCOMPARE(obj.dec0(), dms{ 0 }); 0319 QCOMPARE(obj.name(), "test"); 0320 QCOMPARE(obj.mag(), -1); 0321 QCOMPARE(obj.longname(), "long test"); 0322 QCOMPARE(obj.catalogIdentifier(), "NGC 100"); 0323 QCOMPARE(obj.a(), 10); 0324 QCOMPARE(obj.b(), 11); 0325 QCOMPARE(obj.pa(), 111); 0326 QCOMPARE(obj.flux(), 0); 0327 0328 success_add = m_manager.add_object(cat.id, obj); 0329 QVERIFY2(success_add.first, "Can add the same object twice = update!"); 0330 QCOMPARE(m_manager.get_objects_in_catalog(SkyObject::STAR, cat.id, 99, 1).size(), 0331 1); 0332 0333 const CatalogObject obj_direct{ 0334 {}, SkyObject::STAR, dms{ 1 }, dms{ 11 }, -1, "test_1", 0335 "long test", "NGC 100", 10, 11, 111, 0 0336 }; 0337 0338 success_add = m_manager.add_object(cat.id, obj_direct); 0339 QVERIFY2(success_add.first, "Can add predefined catalog object."); 0340 0341 const auto obj_retr = m_manager.find_objects_by_name(cat.id, "test_1", 1).front(); 0342 QCOMPARE(obj_direct.type(), obj_retr.type()); 0343 QCOMPARE(obj_direct.ra0(), obj_retr.ra0()); 0344 QCOMPARE(obj_direct.dec0(), obj_retr.dec0()); 0345 QCOMPARE(obj_direct.name(), obj_retr.name()); 0346 QCOMPARE(obj_direct.mag(), obj_retr.mag()); 0347 QCOMPARE(obj_direct.longname(), obj_retr.longname()); 0348 QCOMPARE(obj_direct.catalogIdentifier(), obj_retr.catalogIdentifier()); 0349 QCOMPARE(obj_direct.a(), obj_retr.a()); 0350 QCOMPARE(obj_direct.b(), obj_retr.b()); 0351 QCOMPARE(obj_direct.pa(), obj_retr.pa()); 0352 QCOMPARE(obj_direct.flux(), obj_retr.flux()); 0353 0354 const auto &success_copy = m_manager.copy_objects(cat.id, 0); 0355 QVERIFY2(success_copy.first, "Can copy objects."); 0356 0357 QCOMPARE(m_manager.find_objects_by_name(0, "test", 1).size(), 1); 0358 QCOMPARE(m_manager.find_objects_by_name(0, "test", 1).front().getCatalog().id, 0); 0359 0360 QCOMPARE(m_manager.find_objects_by_name(0, "test_1", 1).size(), 1); 0361 QCOMPARE(m_manager.get_objects_in_catalog(SkyObject::STAR, 0).size(), 2); 0362 } 0363 0364 void add_and_remove_object() 0365 { 0366 auto success = 0367 m_manager.add_object(0, SkyObject::STAR, dms{ 0 }, dms{ 0 }, "tester"); 0368 QVERIFY(success.first); 0369 QCOMPARE(m_manager.find_objects_by_name(0, "tester", 1).front().name(), "tester"); 0370 0371 const CatalogObject o{ {}, SkyObject::STAR, dms{ 0 }, dms{ 0 }, 0, "tester_1" }; 0372 success = m_manager.add_object(0, o); 0373 QVERIFY(success.first); 0374 QCOMPARE(m_manager.find_objects_by_name(0, "tester_1", 1).front().getId(), o); 0375 0376 success = m_manager.remove_object(0, o.getObjectId()); 0377 QVERIFY(success.first); 0378 QCOMPARE(m_manager.find_objects_by_name(0, "tester_1", 1).size(), 0); 0379 } 0380 0381 void add_objects() 0382 { 0383 const Catalog cat{ m_manager.find_suitable_catalog_id(), 0384 "test", 0385 1, 0386 "tester", 0387 "test catalog", 0388 "testing catalog", 0389 true, 0390 false, 0391 100 }; 0392 0393 auto success = m_manager.register_catalog(cat); 0394 QVERIFY2(success.first, "Registering a catalog worked."); 0395 0396 const int num_objs{ 1000 }; 0397 std::vector<float> test_mags(num_objs); 0398 std::iota(test_mags.begin(), test_mags.end(), 1); 0399 std::vector<CatalogObject> objects; 0400 std::transform( 0401 test_mags.begin(), test_mags.end(), std::back_inserter(objects), 0402 [](const auto mag) { 0403 return CatalogObject{ {}, SkyObject::STAR, 0404 dms{ 1 }, dms{ 11 }, 0405 -1, QString("test_%1_").arg(mag), 0406 "long test", "NGC 100", 0407 10, 11, 0408 111, 0 }; 0409 }); 0410 0411 auto success_add = m_manager.add_objects(cat.id, objects); 0412 QVERIFY2(success_add.first, "Inserting an object worked."); 0413 QCOMPARE(m_manager.get_catalog_statistics(cat.id).second.total_count, num_objs); 0414 0415 for (const auto &obj : objects) 0416 { 0417 const auto obj_retr = 0418 m_manager.find_objects_by_name(cat.id, obj.name(), 1).front(); 0419 QCOMPARE(obj.type(), obj_retr.type()); 0420 QCOMPARE(obj.ra0(), obj_retr.ra0()); 0421 QCOMPARE(obj.dec0(), obj_retr.dec0()); 0422 QCOMPARE(obj.name(), obj_retr.name()); 0423 QCOMPARE(obj.mag(), obj_retr.mag()); 0424 QCOMPARE(obj.longname(), obj_retr.longname()); 0425 QCOMPARE(obj.catalogIdentifier(), obj_retr.catalogIdentifier()); 0426 QCOMPARE(obj.a(), obj_retr.a()); 0427 QCOMPARE(obj.b(), obj_retr.b()); 0428 QCOMPARE(obj.pa(), obj_retr.pa()); 0429 QCOMPARE(obj.flux(), obj_retr.flux()); 0430 } 0431 } 0432 0433 void concurrent_query() 0434 { 0435 auto f1 = QtConcurrent::run([&] { 0436 const auto &objs = m_manager.get_objects(); 0437 return objs.size() > 0; 0438 }); 0439 0440 auto f2 = QtConcurrent::run([&] { 0441 const auto &objs = m_manager.get_objects(); 0442 return objs.size() > 0; 0443 }); 0444 0445 f1.waitForFinished(); 0446 f2.waitForFinished(); 0447 0448 QVERIFY(f1.result() && f2.result()); 0449 } 0450 0451 void statistics() 0452 { 0453 auto success_add = 0454 m_manager.add_object(user_catalog_id, SkyObject::STAR, dms{ 1 }, dms{ 0 }, 0455 "test", -1, "long test", "NGC 100", 10, 11, 111, 0); 0456 QVERIFY2(success_add.first, "Adding object succeeds."); 0457 0458 success_add = m_manager.add_object(user_catalog_id, SkyObject::SUPERNOVA_REMNANT, 0459 dms{ 1 }, dms{ 0 }, "test", -1, "long test", 0460 "NGC 100", 10, 11, 111, 0); 0461 QVERIFY2(success_add.first, "Adding object succeeds."); 0462 0463 auto stats = m_manager.get_catalog_statistics(0); 0464 QVERIFY2(stats.first, "retrieving stats works"); 0465 QCOMPARE(stats.second.total_count, 2); 0466 QCOMPARE(stats.second.object_counts.at(SkyObject::STAR), 1); 0467 QCOMPARE(stats.second.object_counts.at(SkyObject::SUPERNOVA_REMNANT), 1); 0468 0469 stats = m_manager.get_master_statistics(); 0470 QVERIFY2(stats.first, "retrieving stats works"); 0471 QVERIFY(stats.second.total_count > 0); 0472 QVERIFY(stats.second.object_counts.at(SkyObject::STAR) >= 1); 0473 QVERIFY(stats.second.object_counts.at(SkyObject::SUPERNOVA_REMNANT) >= 1); 0474 } 0475 0476 void color_strings() 0477 { 0478 const std::vector<std::pair<QString, CatalogsDB::CatalogColorMap>> test_data{ 0479 { "#008000", { { "default", "#008000" } } }, 0480 { "#008000;test.colors;#008001", 0481 { { "default", "#008000" }, { "test.colors", "#008001" } } }, 0482 { "#008000;test.colors;#008001;best.colors;#008002", 0483 { { "default", "#008000" }, 0484 { "test.colors", "#008001" }, 0485 { "best.colors", "#008002" } } } 0486 }; 0487 0488 for (const auto &item : test_data) 0489 { 0490 QCOMPARE(CatalogsDB::parse_color_string(item.first), item.second); 0491 0492 QCOMPARE( 0493 CatalogsDB::parse_color_string(CatalogsDB::to_color_string(item.second)), 0494 item.second); // the other way around does not have to be invertible 0495 } 0496 0497 // more than one theme changes the order in the string 0498 const auto &simple = test_data.at(1); 0499 QCOMPARE(CatalogsDB::to_color_string(simple.second), simple.first); 0500 0501 // Check the behavour when a color specification is missing 0502 QCOMPARE((CatalogsDB::parse_color_string("#008000;test.colors")), 0503 (CatalogsDB::CatalogColorMap{ { "default", "#008000" } })); 0504 0505 // no default 0506 QCOMPARE(CatalogsDB::parse_color_string(""), CatalogsDB::CatalogColorMap{}); 0507 QCOMPARE(CatalogsDB::parse_color_string(";test;#008000"), 0508 (CatalogsDB::CatalogColorMap{ { "test", "#008000" } })); 0509 } 0510 0511 void color_database() 0512 { 0513 auto compare_catalog_color_maps = [](CatalogsDB::CatalogColorMap a, 0514 CatalogsDB::CatalogColorMap b) -> void { 0515 for (auto &item : a) 0516 { 0517 QCOMPARE(b[item.first].name(), item.second.name()); 0518 } 0519 0520 for (auto &item : b) 0521 { 0522 QCOMPARE(a[item.first].name(), item.second.name()); 0523 } 0524 }; 0525 0526 auto compare_color_maps = 0527 [compare_catalog_color_maps](CatalogsDB::ColorMap a, 0528 CatalogsDB::ColorMap b) -> void { 0529 for (auto &item : a) 0530 { 0531 compare_catalog_color_maps(b[item.first], item.second); 0532 } 0533 0534 for (auto &item : b) 0535 { 0536 compare_catalog_color_maps(a[item.first], item.second); 0537 } 0538 }; 0539 0540 const auto &colors = m_manager.get_catalog_colors(); 0541 compare_color_maps((CatalogsDB::ColorMap{ 0542 { 1, 0543 { 0544 { "default", "#001000" }, 0545 { "test.colors", "#008000" }, 0546 { "test1.colors", "#008001" }, // overridden 0547 { "test2.colors", "#001002" }, // from catalog table 0548 } }, 0549 { 2, 0550 { 0551 { "test1.colors", "#008002" }, 0552 } } }), 0553 colors); 0554 0555 compare_catalog_color_maps(m_manager.get_catalog_colors(1), colors.at(1)); 0556 0557 // overwrite default 0558 auto new_colors = colors.at(1); 0559 new_colors["test2.colors"] = "#001003"; 0560 0561 const auto &success = m_manager.insert_catalog_colors(1, new_colors); 0562 QVERIFY(success.first); 0563 0564 QCOMPARE(m_manager.get_catalog_colors(1).at("test2.colors"), "#001003"); 0565 0566 auto cat = m_manager.get_catalog(1); 0567 QVERIFY(cat.first); 0568 cat.second.color = "#001004"; 0569 QVERIFY(m_manager.update_catalog_meta(cat.second).first); 0570 QCOMPARE(m_manager.get_catalog_colors(1).at("default"), 0571 "#001000"); // does not change 0572 } 0573 }; 0574 0575 QTEST_GUILESS_MAIN(TestCatalogsDB_DBManager);