// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include #include "Interface/EventsRecord.hpp" #include "Database/Database.hpp" #include "Databases/EventsDB.hpp" #include "module-db/queries/calendar/QueryEventsGet.hpp" #include "module-db/queries/calendar/QueryEventsGetAll.hpp" #include "module-db/queries/calendar/QueryEventsGetAllLimited.hpp" #include "module-db/queries/calendar/QueryEventsGetFiltered.hpp" #include "module-db/queries/calendar/QueryEventsAdd.hpp" #include "module-db/queries/calendar/QueryEventsRemove.hpp" #include "module-db/queries/calendar/QueryEventsRemoveICS.hpp" #include "module-db/queries/calendar/QueryEventsEdit.hpp" #include "module-db/queries/calendar/QueryEventsEditICS.hpp" #include "module-db/queries/calendar/QueryEventsSelectFirstUpcoming.hpp" #include #include #include #include using namespace std::chrono_literals; static auto remove_events(EventsDB &db) -> bool { auto count = db.events.count(); auto records = db.events.getLimitOffset(0, count); bool ret = true; for (auto rec : records) { ret = ret && db.events.removeById(rec.ID); } return ret; } TEST_CASE("Events Record tests") { Database::initialize(); const auto eventsPath = (std::filesystem::path{"user"} / "events.db"); if (std::filesystem::exists(eventsPath)) { REQUIRE(std::filesystem::remove(eventsPath)); } EventsDB eventsDb{eventsPath.c_str()}; REQUIRE(eventsDb.isInitialized()); SECTION("Default Constructor") { EventsRecord testRec; REQUIRE(testRec.title == ""); REQUIRE(testRec.reminder == 0); REQUIRE(testRec.repeat == 0); } EventsTableRow testRow = {{1}, .UID = "test1", .title = "Event1", .date_from = TimePointFromString("2019-10-20 14:25:00"), .date_till = TimePointFromString("2019-10-20 15:36:00"), .reminder = static_cast(Reminder::five_min_before), .repeat = static_cast(Repeat::never), .reminder_fired = TimePointFromString("2019-10-20 14:20:00"), .provider_type = "PurePhone", .provider_id = "testID", .provider_iCalUid = "test6"}; EventsTableRow testRow2 = {{2}, .UID = "test2", .title = "Event2", .date_from = TimePointFromString("2019-10-21 14:24:00"), .date_till = TimePointFromString("2019-10-21 15:36:00"), .reminder = static_cast(Reminder::five_min_before), .repeat = static_cast(Repeat::never), .reminder_fired = TIME_POINT_INVALID, .provider_type = "PurePhone", .provider_id = "testID", .provider_iCalUid = "test6"}; EventsTableRow testRow3 = {{3}, .UID = "test3", .title = "Event3", .date_from = TimePointFromString("2019-10-22 14:25:00"), .date_till = TimePointFromString("2019-10-22 15:36:00"), .reminder = static_cast(Reminder::five_min_before), .repeat = static_cast(Repeat::never), .reminder_fired = TimePointFromString("2019-10-22 14:20:00"), .provider_type = "PurePhone", .provider_id = "testID", .provider_iCalUid = "test6"}; EventsTableRow testRow4 = {{4}, .UID = "test4", .title = "Event4", .date_from = TimePointFromString("2019-10-23 14:25:00"), .date_till = TimePointFromString("2019-10-23 15:36:00"), .reminder = static_cast(Reminder::five_min_before), .repeat = static_cast(Repeat::never), .reminder_fired = TimePointFromString("2019-10-23 14:20:00"), .provider_type = "PurePhone", .provider_id = "testID", .provider_iCalUid = "test6"}; EventsTableRow testRow5 = {{5}, .UID = "test5", .title = "Event5", .date_from = TimePointFromString("2019-10-24 14:25:00"), .date_till = TimePointFromString("2019-10-24 15:36:00"), .reminder = static_cast(Reminder::five_min_before), .repeat = static_cast(Repeat::never), .reminder_fired = TIME_POINT_INVALID, .provider_type = "PurePhone", .provider_id = "testID", .provider_iCalUid = "test6"}; EventsTableRow testRow6 = {{6}, .UID = "test6", .title = "Event6", .date_from = TimePointFromString("2019-10-24 14:25:00"), .date_till = TimePointFromString("2019-10-24 15:36:00"), .reminder = static_cast(Reminder::five_min_before), .repeat = static_cast(Repeat::never), .reminder_fired = TimePointFromString("2019-10-24 14:20:00"), .provider_type = "PurePhone", .provider_id = "testID", .provider_iCalUid = "test6"}; auto check_record = [](const EventsRecord &actual, const EventsRecord &expected) { CHECK(actual.UID == expected.UID); CHECK(actual.title == expected.title); CHECK(TimePointToString(actual.date_from) == TimePointToString(expected.date_from)); CHECK(TimePointToString(actual.date_till) == TimePointToString(expected.date_till)); CHECK(actual.reminder == expected.reminder); CHECK(actual.repeat == expected.repeat); CHECK(actual.reminder_fired == expected.reminder_fired); CHECK(actual.provider_type == expected.provider_type); CHECK(actual.provider_id == expected.provider_id); CHECK(actual.provider_iCalUid == expected.provider_iCalUid); CHECK(actual.isValid()); }; SECTION("Constructor from EventsTableRow") { EventsRecord testRecord(testRow); check_record(testRecord, testRow); } EventsRecordInterface eventsRecordInterface(&eventsDb); auto numberOfEvents = eventsRecordInterface.GetCount(); REQUIRE(numberOfEvents == 0); auto testRecord = EventsRecord(testRow); auto testRecord2 = EventsRecord(testRow2); auto testRecord3 = EventsRecord(testRow3); auto testRecord4 = EventsRecord(testRow4); auto testRecord5 = EventsRecord(testRow5); auto testRecord6 = EventsRecord(testRow6); REQUIRE(eventsRecordInterface.Add(testRecord)); REQUIRE(eventsRecordInterface.Add(testRecord2)); REQUIRE(eventsRecordInterface.Add(testRecord3)); REQUIRE(eventsRecordInterface.Add(testRecord4)); REQUIRE(eventsRecordInterface.Add(testRecord5)); REQUIRE(eventsRecordInterface.Add(testRecord6)); numberOfEvents = eventsRecordInterface.GetCount(); REQUIRE(numberOfEvents == 6); SECTION("Get entry by ID") { auto entry = eventsRecordInterface.GetByID(testRecord3.ID); check_record(entry, testRecord3); } SECTION("Get count filtered") { auto count = eventsRecordInterface.GetCountFiltered(testRecord3.date_from, testRecord5.date_from); CHECK(count == 2); } SECTION("Get count") { auto count = eventsRecordInterface.GetCount(); CHECK(count == 6); } SECTION("Get entry - invalid ID") { auto entry = eventsRecordInterface.GetByID(100); CHECK(entry.ID == DB_ID_NONE); CHECK(entry.title == ""); CHECK(entry.date_from == TIME_POINT_INVALID); CHECK(entry.date_till == TIME_POINT_INVALID); CHECK(entry.reminder == 0); CHECK(entry.repeat == 0); CHECK(entry.reminder_fired == TIME_POINT_INVALID); CHECK(entry.provider_type == ""); CHECK(entry.provider_id == ""); CHECK(entry.provider_iCalUid == ""); CHECK_FALSE(entry.isValid()); } SECTION("Entry remove") { REQUIRE(eventsRecordInterface.RemoveByID(testRecord4.ID)); numberOfEvents = eventsRecordInterface.GetCount(); REQUIRE(numberOfEvents == 5); CHECK_NOTHROW(eventsRecordInterface.GetByID(testRecord4.ID)); } SECTION("Entry remove by uid") { REQUIRE(eventsRecordInterface.RemoveByUID(testRecord4.UID)); numberOfEvents = eventsRecordInterface.GetCount(); REQUIRE(numberOfEvents == 5); CHECK_NOTHROW(eventsRecordInterface.GetByID(testRecord4.ID)); } SECTION("Entry update") { auto entryToUpdate = eventsRecordInterface.GetByID(testRecord5.ID); entryToUpdate.title = "newTitle"; entryToUpdate.date_from = TimePointFromString("2019-12-31 23:59:00"); entryToUpdate.date_till = TimePointFromString("2019-12-31 23:59:00"); REQUIRE(eventsRecordInterface.Update(entryToUpdate)); auto entry = eventsRecordInterface.GetByID(entryToUpdate.ID); check_record(entry, entryToUpdate); } SECTION("Entry update by uid") { auto entryToUpdate = eventsRecordInterface.GetByID(testRecord3.ID); entryToUpdate.title = "newTitle"; entryToUpdate.date_from = TimePointFromString("2019-12-31 23:59:00"); entryToUpdate.date_till = TimePointFromString("2019-12-31 23:59:00"); REQUIRE(eventsRecordInterface.UpdateByUID(entryToUpdate)); auto entry = eventsRecordInterface.GetByID(entryToUpdate.ID); check_record(entry, entryToUpdate); } SECTION("Get entries") { SECTION("Get records using valid offset/limit parameters") { auto retOffsetLimit = eventsRecordInterface.GetLimitOffset(0, numberOfEvents); REQUIRE(retOffsetLimit->size() == numberOfEvents); CHECK((*retOffsetLimit)[0].ID == testRecord.ID); CHECK((*retOffsetLimit)[1].ID == testRecord2.ID); CHECK((*retOffsetLimit)[2].ID == testRecord3.ID); CHECK((*retOffsetLimit)[3].ID == testRecord4.ID); CHECK((*retOffsetLimit)[4].ID == testRecord5.ID); CHECK((*retOffsetLimit)[5].ID == testRecord6.ID); } SECTION("Get table rows using bigger limit parameters") { auto retOffsetLimit = eventsRecordInterface.GetLimitOffset(0, 100); REQUIRE(retOffsetLimit->size() == numberOfEvents); } SECTION("Get table rows using invalid offset/limit parameters(should return empty object)") { auto retOffsetLimit = eventsRecordInterface.GetLimitOffset(6, 10); REQUIRE(retOffsetLimit->size() == 0); } SECTION("0 - get all") { auto retOffsetLimit = eventsRecordInterface.GetLimitOffset(0, 0); REQUIRE(retOffsetLimit->size() == numberOfEvents); } SECTION("Get table rows by SELECT") { auto retOffsetLimit = eventsRecordInterface.Select( TimePointFromString("2019-10-19 14:24:00"), TimePointFromString("2019-10-27 15:36:00"), 0, UINT32_MAX); REQUIRE(retOffsetLimit.size() == numberOfEvents); } SECTION("Get table rows by SELECT limited") { auto retOffsetLimit = eventsRecordInterface.Select( TimePointFromString("2019-10-19 14:24:00"), TimePointFromString("2019-10-27 15:36:00"), 0, 3); REQUIRE(retOffsetLimit.size() == 3); } SECTION("Get table rows by SELECT limited by date") { auto retOffsetLimit = eventsRecordInterface.Select( TimePointFromString("2019-10-19 14:24:00"), TimePointFromString("2019-10-22 15:36:00"), 0, UINT32_MAX); REQUIRE(retOffsetLimit.size() == 2); } SECTION("Get table rows by SELECT invalid") { auto retOffsetLimit = eventsRecordInterface.Select( TimePointFromString("2010-10-20 14:24:00"), TimePointFromString("2010-10-20 15:36:00"), 0, UINT32_MAX); REQUIRE(retOffsetLimit.size() == 0); } SECTION("Get records using valid offset/limit date parameters") { auto recordWithEarliestDate = eventsRecordInterface.GetByID(testRecord3.ID); recordWithEarliestDate.date_from = TimePointFromString("1990-10-23 14:25:00"); REQUIRE(eventsRecordInterface.Update(recordWithEarliestDate)); auto retOffsetLimit = eventsRecordInterface.GetLimitOffsetByDate(0, numberOfEvents); REQUIRE(retOffsetLimit.size() == numberOfEvents); CHECK((retOffsetLimit)[0].ID == testRecord3.ID); CHECK((retOffsetLimit)[1].ID == testRecord.ID); CHECK((retOffsetLimit)[2].ID == testRecord2.ID); CHECK((retOffsetLimit)[3].ID == testRecord4.ID); CHECK((retOffsetLimit)[4].ID == testRecord5.ID); CHECK((retOffsetLimit)[5].ID == testRecord6.ID); } SECTION("Get records using valid offset/limit date parameters") { auto recordWithEarliestDate = eventsRecordInterface.GetByID(testRecord3.ID); recordWithEarliestDate.date_from = TimePointFromString("1990-10-23 14:25:00"); recordWithEarliestDate.date_till = TimePointFromString("1990-10-23 14:25:00"); REQUIRE(eventsRecordInterface.Update(recordWithEarliestDate)); auto retOffsetLimit = eventsRecordInterface.GetLimitOffsetByDate(0, numberOfEvents); REQUIRE(retOffsetLimit.size() == numberOfEvents); CHECK((retOffsetLimit)[0].ID == recordWithEarliestDate.ID); CHECK((retOffsetLimit)[1].ID == testRecord.ID); CHECK((retOffsetLimit)[2].ID == testRecord2.ID); CHECK((retOffsetLimit)[3].ID == testRecord4.ID); CHECK((retOffsetLimit)[4].ID == testRecord5.ID); CHECK((retOffsetLimit)[5].ID == testRecord6.ID); } } SECTION("Entry add repeated") { if (eventsRecordInterface.GetCount() > 0) { REQUIRE(remove_events(eventsDb)); } REQUIRE(eventsRecordInterface.GetCount() == 0); uint32_t testRecordActualId = numberOfEvents + 1; testRecord3.ID = testRecordActualId; auto expectedRecordData = testRecord3; auto set_repeat = [&](Repeat option, uint32_t count) { expectedRecordData.repeat = static_cast(option); REQUIRE(eventsRecordInterface.Add(expectedRecordData)); auto entries = eventsRecordInterface.GetLimitOffset(0, 0); REQUIRE(entries->size() == count); return *entries; }; SECTION("Daily, count = 7") { uint32_t expectedEventsCount = 7; auto entries = set_repeat(Repeat::daily, expectedEventsCount); for (auto entry : entries) { check_record(entry, expectedRecordData); expectedRecordData.date_from = expectedRecordData.date_from + 24h; expectedRecordData.date_till = expectedRecordData.date_till + 24h; } } SECTION("Weekly, count = 4") { uint32_t expectedEventsCount = 4; auto entries = set_repeat(Repeat::weekly, expectedEventsCount); for (auto entry : entries) { check_record(entry, expectedRecordData); expectedRecordData.date_from = expectedRecordData.date_from + (7 * 24h); expectedRecordData.date_till = expectedRecordData.date_till + (7 * 24h); } } SECTION("Biweekly, count = 4") { uint32_t expectedEventsCount = 4; auto entries = set_repeat(Repeat::biweekly, expectedEventsCount); for (auto entry : entries) { check_record(entry, expectedRecordData); expectedRecordData.date_from = expectedRecordData.date_from + (2 * 7 * 24h); expectedRecordData.date_till = expectedRecordData.date_till + (2 * 7 * 24h); } } SECTION("Monthly, count = 12") { uint32_t expectedEventsCount = 12; expectedRecordData.date_from = TimePointFromString("2019-01-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-01-05 17:00:00"); auto entries = set_repeat(Repeat::monthly, expectedEventsCount); check_record(entries[0], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-02-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-02-05 17:00:00"); check_record(entries[1], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-03-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-03-05 17:00:00"); check_record(entries[2], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-04-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-04-05 17:00:00"); check_record(entries[3], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-05-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-05-05 17:00:00"); check_record(entries[4], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-06-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-06-05 17:00:00"); check_record(entries[5], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-07-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-07-05 17:00:00"); check_record(entries[6], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-08-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-08-05 17:00:00"); check_record(entries[7], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-09-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-09-05 17:00:00"); check_record(entries[8], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-10-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-10-05 17:00:00"); check_record(entries[9], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-11-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-11-05 17:00:00"); check_record(entries[10], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-12-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-12-05 17:00:00"); check_record(entries[11], expectedRecordData); } SECTION("Yearly, count = 4") { uint32_t expectedEventsCount = 4; expectedRecordData.date_from = TimePointFromString("2019-02-28 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-02-28 17:00:00"); auto entries = set_repeat(Repeat::yearly, expectedEventsCount); check_record(entries[0], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2020-02-28 15:00:00"); expectedRecordData.date_till = TimePointFromString("2020-02-28 17:00:00"); check_record(entries[1], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2021-02-28 15:00:00"); expectedRecordData.date_till = TimePointFromString("2021-02-28 17:00:00"); check_record(entries[2], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2022-02-28 15:00:00"); expectedRecordData.date_till = TimePointFromString("2022-02-28 17:00:00"); check_record(entries[3], expectedRecordData); } } SECTION("Entry update repeated") { if (eventsRecordInterface.GetCount() > 0) { REQUIRE(remove_events(eventsDb)); } REQUIRE(eventsRecordInterface.GetCount() == 0); uint32_t testRecordActualId = numberOfEvents + 1; testRecord.ID = testRecordActualId; REQUIRE(eventsRecordInterface.Add(testRecord)); auto expectedRecordData = eventsRecordInterface.GetByID(testRecord.ID); auto set_repeat = [&](Repeat option, uint32_t count) { expectedRecordData.repeat = static_cast(option); REQUIRE(eventsRecordInterface.Update(expectedRecordData)); auto entries = eventsRecordInterface.GetLimitOffset(0, 0); REQUIRE(entries->size() == count); return *entries; }; SECTION("Daily, count = 7") { uint32_t expectedEventsCount = 7; auto entries = set_repeat(Repeat::daily, expectedEventsCount); for (auto entry : entries) { check_record(entry, expectedRecordData); expectedRecordData.date_from = expectedRecordData.date_from + 24h; expectedRecordData.date_till = expectedRecordData.date_till + 24h; } } SECTION("Weekly, count = 4") { uint32_t expectedEventsCount = 4; auto entries = set_repeat(Repeat::weekly, expectedEventsCount); for (auto entry : entries) { check_record(entry, expectedRecordData); expectedRecordData.date_from = expectedRecordData.date_from + (7 * 24h); expectedRecordData.date_till = expectedRecordData.date_till + (7 * 24h); } } SECTION("Biweekly, count = 4") { uint32_t expectedEventsCount = 4; auto entries = set_repeat(Repeat::biweekly, expectedEventsCount); for (auto entry : entries) { check_record(entry, expectedRecordData); expectedRecordData.date_from = expectedRecordData.date_from + (2 * 7 * 24h); expectedRecordData.date_till = expectedRecordData.date_till + (2 * 7 * 24h); } } SECTION("Monthly, count = 12") { uint32_t expectedEventsCount = 12; expectedRecordData.date_from = TimePointFromString("2019-01-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-01-05 17:00:00"); auto entries = set_repeat(Repeat::monthly, expectedEventsCount); check_record(entries[0], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-02-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-02-05 17:00:00"); check_record(entries[1], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-03-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-03-05 17:00:00"); check_record(entries[2], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-04-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-04-05 17:00:00"); check_record(entries[3], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-05-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-05-05 17:00:00"); check_record(entries[4], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-06-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-06-05 17:00:00"); check_record(entries[5], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-07-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-07-05 17:00:00"); check_record(entries[6], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-08-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-08-05 17:00:00"); check_record(entries[7], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-09-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-09-05 17:00:00"); check_record(entries[8], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-10-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-10-05 17:00:00"); check_record(entries[9], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-11-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-11-05 17:00:00"); check_record(entries[10], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-12-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-12-05 17:00:00"); check_record(entries[11], expectedRecordData); } SECTION("Yearly, count = 4") { uint32_t expectedEventsCount = 4; expectedRecordData.date_from = TimePointFromString("2019-02-28 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-02-28 17:00:00"); auto entries = set_repeat(Repeat::yearly, expectedEventsCount); check_record(entries[0], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2020-02-28 15:00:00"); expectedRecordData.date_till = TimePointFromString("2020-02-28 17:00:00"); check_record(entries[1], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2021-02-28 15:00:00"); expectedRecordData.date_till = TimePointFromString("2021-02-28 17:00:00"); check_record(entries[2], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2022-02-28 15:00:00"); expectedRecordData.date_till = TimePointFromString("2022-02-28 17:00:00"); check_record(entries[3], expectedRecordData); } } SECTION("Entry updateICS repeated") { if (eventsRecordInterface.GetCount() > 0) { REQUIRE(remove_events(eventsDb)); } REQUIRE(eventsRecordInterface.GetCount() == 0); REQUIRE(eventsRecordInterface.Add(testRecord)); auto expectedRecordData = eventsRecordInterface.GetByUID(testRecord.UID); auto set_repeat = [&](Repeat option, uint32_t count) { expectedRecordData.repeat = static_cast(option); REQUIRE(eventsRecordInterface.UpdateByUID(expectedRecordData)); auto entries = eventsRecordInterface.GetLimitOffset(0, 0); REQUIRE(entries->size() == count); return *entries; }; SECTION("Daily, count = 7") { uint32_t expectedEventsCount = 7; auto entries = set_repeat(Repeat::daily, expectedEventsCount); for (auto entry : entries) { check_record(entry, expectedRecordData); expectedRecordData.date_from = expectedRecordData.date_from + 24h; expectedRecordData.date_till = expectedRecordData.date_till + 24h; } } SECTION("Weekly, count = 4") { uint32_t expectedEventsCount = 4; auto entries = set_repeat(Repeat::weekly, expectedEventsCount); for (auto entry : entries) { check_record(entry, expectedRecordData); expectedRecordData.date_from = expectedRecordData.date_from + (7 * 24h); expectedRecordData.date_till = expectedRecordData.date_till + (7 * 24h); } } SECTION("Biweekly, count = 4") { uint32_t expectedEventsCount = 4; auto entries = set_repeat(Repeat::biweekly, expectedEventsCount); for (auto entry : entries) { check_record(entry, expectedRecordData); expectedRecordData.date_from = expectedRecordData.date_from + (2 * 7 * 24h); expectedRecordData.date_till = expectedRecordData.date_till + (2 * 7 * 24h); } } SECTION("Monthly, count = 12") { uint32_t expectedEventsCount = 12; expectedRecordData.date_from = TimePointFromString("2019-01-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-01-05 17:00:00"); auto entries = set_repeat(Repeat::monthly, expectedEventsCount); check_record(entries[0], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-02-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-02-05 17:00:00"); check_record(entries[1], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-03-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-03-05 17:00:00"); check_record(entries[2], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-04-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-04-05 17:00:00"); check_record(entries[3], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-05-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-05-05 17:00:00"); check_record(entries[4], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-06-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-06-05 17:00:00"); check_record(entries[5], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-07-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-07-05 17:00:00"); check_record(entries[6], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-08-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-08-05 17:00:00"); check_record(entries[7], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-09-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-09-05 17:00:00"); check_record(entries[8], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-10-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-10-05 17:00:00"); check_record(entries[9], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-11-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-11-05 17:00:00"); check_record(entries[10], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2019-12-05 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-12-05 17:00:00"); check_record(entries[11], expectedRecordData); } SECTION("Yearly, count = 4") { uint32_t expectedEventsCount = 4; expectedRecordData.date_from = TimePointFromString("2019-02-28 15:00:00"); expectedRecordData.date_till = TimePointFromString("2019-02-28 17:00:00"); auto entries = set_repeat(Repeat::yearly, expectedEventsCount); check_record(entries[0], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2020-02-28 15:00:00"); expectedRecordData.date_till = TimePointFromString("2020-02-28 17:00:00"); check_record(entries[1], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2021-02-28 15:00:00"); expectedRecordData.date_till = TimePointFromString("2021-02-28 17:00:00"); check_record(entries[2], expectedRecordData); expectedRecordData.date_from = TimePointFromString("2022-02-28 15:00:00"); expectedRecordData.date_till = TimePointFromString("2022-02-28 17:00:00"); check_record(entries[3], expectedRecordData); } } SECTION("Select first upcoming event") { TimePoint start_date = TimePointFromString("2019-10-19 14:24:00"); auto nextUpcoming = eventsRecordInterface.SelectFirstUpcoming(start_date, start_date); REQUIRE(nextUpcoming.size() == 1); EventsRecord nextEventsRecord = nextUpcoming.at(0); REQUIRE(nextEventsRecord.ID == 2); nextEventsRecord.reminder_fired = TimePointFromString("2018-12-31 23:59:00"); REQUIRE(eventsRecordInterface.Update(nextEventsRecord)); start_date = TimePointFromString("2019-10-23 14:24:00"); nextUpcoming = eventsRecordInterface.SelectFirstUpcoming(start_date, start_date); REQUIRE(nextUpcoming.size() == 1); REQUIRE(nextEventsRecord.ID == 2); } ///====TEST QUERY==== auto getQuery = [&](uint32_t id, EventsRecord expected_record) { auto query = std::make_shared(id); auto ret = eventsRecordInterface.runQuery(query); auto result = dynamic_cast(ret.get()); REQUIRE(result != nullptr); auto record = result->getResult(); check_record(record, expected_record); }; SECTION("Check Get via query") { getQuery(testRecord.ID, testRecord); getQuery(testRecord3.ID, testRecord3); getQuery(testRecord6.ID, testRecord6); } [[maybe_unused]] auto getAll = [&](std::vector expected_records, uint32_t expectedAllRecsNumber) { auto query = std::make_shared(); auto ret = eventsRecordInterface.runQuery(query); auto result = dynamic_cast(ret.get()); REQUIRE(result != nullptr); auto records = result->getResult(); REQUIRE(records.size() == expectedAllRecsNumber); auto expected_record = expected_records.begin(); std::for_each(records.begin(), records.end(), [&expected_record](const EventsRecord &record) { CHECK(record.ID == expected_record->ID); CHECK(record.UID == expected_record->UID); CHECK(record.title == expected_record->title); CHECK(TimePointToString(record.date_from) == TimePointToString(expected_record->date_from)); CHECK(TimePointToString(record.date_till) == TimePointToString(expected_record->date_till)); CHECK(record.reminder == expected_record->reminder); CHECK(record.repeat == expected_record->repeat); CHECK(record.reminder_fired == expected_record->reminder_fired); CHECK(record.provider_type == expected_record->provider_type); CHECK(record.provider_id == expected_record->provider_id); CHECK(record.provider_iCalUid == expected_record->provider_iCalUid); CHECK(record.isValid()); expected_record++; }); }; SECTION("Get All via query") { std::vector expectedRecords; expectedRecords.push_back(testRecord); expectedRecords.push_back(testRecord2); expectedRecords.push_back(testRecord3); expectedRecords.push_back(testRecord4); expectedRecords.push_back(testRecord5); expectedRecords.push_back(testRecord6); getAll(expectedRecords, numberOfEvents); } auto getFiltered = [&](TimePoint filter_from, TimePoint filter_till, std::vector expected_records) { auto query = std::make_shared(filter_from, filter_till); auto ret = eventsRecordInterface.runQuery(query); auto result = dynamic_cast(ret.get()); REQUIRE(result != nullptr); auto records = result->getResult(); REQUIRE(records.size() == expected_records.size()); auto count = result->getCountResult(); REQUIRE(count == expected_records.size()); auto expected_record = expected_records.begin(); std::for_each(records.begin(), records.end(), [&expected_record](const EventsRecord &record) { CHECK(record.ID == expected_record->ID); CHECK(record.UID == expected_record->UID); CHECK(record.title == expected_record->title); CHECK(TimePointToString(record.date_from) == TimePointToString(expected_record->date_from)); CHECK(TimePointToString(record.date_till) == TimePointToString(expected_record->date_till)); CHECK(record.reminder == expected_record->reminder); CHECK(record.repeat == expected_record->repeat); CHECK(record.reminder_fired == expected_record->reminder_fired); CHECK(record.provider_type == expected_record->provider_type); CHECK(record.provider_id == expected_record->provider_id); CHECK(record.provider_iCalUid == expected_record->provider_iCalUid); CHECK(record.isValid()); expected_record++; }); }; SECTION("GetFiltered via query") { auto startDate = testRecord2.date_from; auto endDate = testRecord5.date_till; std::vector expectedFilteredRecords; expectedFilteredRecords.push_back(testRecord2); expectedFilteredRecords.push_back(testRecord3); expectedFilteredRecords.push_back(testRecord4); getFiltered(startDate, endDate, expectedFilteredRecords); } auto getAllLimited = [&](uint32_t offset, uint32_t limit, std::vector expected_records, uint32_t expectedAllRecsNumber) { auto query = std::make_shared(offset, limit); auto ret = eventsRecordInterface.runQuery(query); auto result = dynamic_cast(ret.get()); REQUIRE(result != nullptr); auto records = result->getResult(); REQUIRE(records.size() == limit); auto count = result->getCountResult(); CHECK(count == expectedAllRecsNumber); auto expected_record = expected_records.begin(); std::for_each(records.begin(), records.end(), [&expected_record](const EventsRecord &record) { CHECK(record.ID == expected_record->ID); CHECK(record.UID == expected_record->UID); CHECK(record.title == expected_record->title); CHECK(TimePointToString(record.date_from) == TimePointToString(expected_record->date_from)); CHECK(TimePointToString(record.date_till) == TimePointToString(expected_record->date_till)); CHECK(record.reminder == expected_record->reminder); CHECK(record.repeat == expected_record->repeat); CHECK(record.reminder_fired == expected_record->reminder_fired); CHECK(record.provider_type == expected_record->provider_type); CHECK(record.provider_id == expected_record->provider_id); CHECK(record.provider_iCalUid == expected_record->provider_iCalUid); CHECK(record.isValid()); expected_record++; }); }; SECTION("Get All Limited via query") { std::vector expectedRecords; expectedRecords.push_back(testRecord2); expectedRecords.push_back(testRecord3); expectedRecords.push_back(testRecord4); expectedRecords.push_back(testRecord5); uint32_t limit = 4; getAllLimited(testRecord2.ID - 1, limit, expectedRecords, numberOfEvents); } auto AddQuery = [&](EventsRecord record) { auto query = std::make_shared(record); auto ret = eventsRecordInterface.runQuery(query); auto result = dynamic_cast(ret.get()); REQUIRE(result != nullptr); REQUIRE(result->getResult()); auto entry = eventsRecordInterface.GetByID(record.ID); check_record(entry, record); }; SECTION("Add via query") { EventsTableRow testRow7 = {{7}, .UID = "test7", .title = "Event7", .date_from = TimePointFromString("2019-11-24 14:25:00"), .date_till = TimePointFromString("2019-12-24 15:36:00"), .reminder = static_cast(Reminder::five_min_before), .repeat = static_cast(Repeat::never), .reminder_fired = TimePointFromString("2019-10-24 14:20:00"), .provider_type = "PurePhone", .provider_id = "testID", .provider_iCalUid = "test6"}; auto testRecord7 = EventsRecord(testRow7); AddQuery(testRecord7); } auto RemoveQuery = [&](uint32_t id) { auto query = std::make_shared(id); auto ret = eventsRecordInterface.runQuery(query); auto result = dynamic_cast(ret.get()); REQUIRE(result != nullptr); REQUIRE(result->getResult()); REQUIRE_NOTHROW(eventsRecordInterface.GetByID(id)); }; SECTION("Remove via query") { RemoveQuery(testRecord2.ID); REQUIRE_NOTHROW(eventsRecordInterface.GetByID(testRecord2.ID)); std::vector expectedRecords; expectedRecords.push_back(testRecord); expectedRecords.push_back(testRecord3); expectedRecords.push_back(testRecord4); expectedRecords.push_back(testRecord5); expectedRecords.push_back(testRecord6); getAll(expectedRecords, numberOfEvents - 1); } auto RemoveQueryICS = [&](std::string uid) { auto query = std::make_shared(uid); auto ret = eventsRecordInterface.runQuery(query); auto result = dynamic_cast(ret.get()); REQUIRE(result != nullptr); REQUIRE(result->getResult()); REQUIRE_NOTHROW(eventsRecordInterface.GetByUID(uid)); }; SECTION("RemoveICS via query") { RemoveQueryICS(testRecord2.UID); REQUIRE_NOTHROW(eventsRecordInterface.GetByUID(testRecord2.UID)); std::vector expectedRecords; expectedRecords.push_back(testRecord); expectedRecords.push_back(testRecord3); expectedRecords.push_back(testRecord4); expectedRecords.push_back(testRecord5); expectedRecords.push_back(testRecord6); getAll(expectedRecords, numberOfEvents - 1); } auto EditQuery = [&](uint32_t id, EventsRecord record) { auto entryToUpdate = eventsRecordInterface.GetByID(id); entryToUpdate.title = record.title; entryToUpdate.date_from = record.date_from; entryToUpdate.date_till = record.date_till; entryToUpdate.reminder = record.reminder; entryToUpdate.repeat = record.repeat; entryToUpdate.provider_type = record.provider_type; entryToUpdate.provider_id = record.provider_id; entryToUpdate.provider_iCalUid = record.provider_iCalUid; auto query = std::make_shared(entryToUpdate); auto ret = eventsRecordInterface.runQuery(query); auto result = dynamic_cast(ret.get()); REQUIRE(result != nullptr); auto entry = eventsRecordInterface.GetByID(entryToUpdate.ID); record.ID = entry.ID; record.UID = entry.UID; check_record(entry, record); }; SECTION("Update via query") { EditQuery(testRecord.ID, testRecord); EditQuery(testRecord3.ID, testRecord3); EditQuery(testRecord6.ID, testRecord6); } auto EditQueryICS = [&](std::string uid, EventsRecord recordUpdateData) { auto entryToUpdate = eventsRecordInterface.GetByUID(uid); entryToUpdate.title = recordUpdateData.title; entryToUpdate.date_from = recordUpdateData.date_from; entryToUpdate.date_till = recordUpdateData.date_till; entryToUpdate.reminder = recordUpdateData.reminder; entryToUpdate.repeat = recordUpdateData.repeat; entryToUpdate.provider_type = recordUpdateData.provider_type; entryToUpdate.provider_id = recordUpdateData.provider_id; entryToUpdate.provider_iCalUid = recordUpdateData.provider_iCalUid; auto query = std::make_shared(entryToUpdate); auto ret = eventsRecordInterface.runQuery(query); auto result = dynamic_cast(ret.get()); REQUIRE(result != nullptr); auto entry = eventsRecordInterface.GetByID(entryToUpdate.ID); recordUpdateData.ID = entry.ID; recordUpdateData.UID = entry.UID; check_record(entry, recordUpdateData); }; SECTION("Update ICS via query") { EditQueryICS(testRecord.UID, testRecord); EditQueryICS(testRecord3.UID, testRecord3); EditQueryICS(testRecord6.UID, testRecord6); } [[maybe_unused]] auto selectFirstUpcomingEvent = [&](TimePoint filter_from, TimePoint filter_till) { auto query = std::make_shared(filter_from, filter_till); auto ret = eventsRecordInterface.runQuery(query); auto result = dynamic_cast(ret.get()); REQUIRE(result != nullptr); auto records = result->getResult(); return records; }; SECTION("Select first upcoming via query") { auto date_from = TimePointFromString("2019-10-19 14:24:00"); auto date_till = TimePointFromString("2026-10-20 14:24:00"); auto records = selectFirstUpcomingEvent(date_from, date_till); REQUIRE(records.size() == 1); auto firstEvent = records.at(0); REQUIRE(firstEvent.ID == 2); date_from = TimePointFromString("2025-11-10 14:24:00"); date_till = TimePointFromString("2026-10-20 14:24:00"); records = selectFirstUpcomingEvent(date_from, date_till); REQUIRE(records.size() == 0); } Database::deinitialize(); }