Files
MuditaOS/module-db/tests/ThreadRecord_tests.cpp
Borys Jelenski b00efa685b [EGD-5115] Fix dangling ptrs in module-db tests
The dangling ptrs derefencing freed memory has been fixed.
They caused the tests to trigger the ASan. Additonally, in some tests
where DB objects were allocated dynamically, they are now allocated
automatically on the stack to simplify the code.
2021-02-04 16:45:50 +01:00

264 lines
9.7 KiB
C++

// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include <catch2/catch.hpp>
#include "Database/Database.hpp"
#include "Databases/ContactsDB.hpp"
#include "Databases/SmsDB.hpp"
#include "Interface/ContactRecord.hpp"
#include "Interface/SMSRecord.hpp"
#include "Interface/ThreadRecord.hpp"
#include "queries/messages/threads/QueryThreadMarkAsRead.hpp"
#include "queries/messages/threads/QueryThreadsSearchForList.hpp"
#include "queries/messages/threads/QueryThreadGetByID.hpp"
#include "queries/messages/threads/QueryThreadGetByContactID.hpp"
#include "queries/messages/threads/QueryThreadGetByNumber.hpp"
#include "queries/messages/threads/QueryThreadRemove.hpp"
#include "queries/messages/threads/QueryThreadsGet.hpp"
#include "queries/messages/sms/QuerySMSGetLastByThreadID.hpp"
#include <vfs.hpp>
#include <purefs/filesystem_paths.hpp>
#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <cstring>
TEST_CASE("Thread Record tests")
{
Database::initialize();
const auto contactsPath = purefs::dir::getUserDiskPath() / "contacts.db";
const auto smsPath = purefs::dir::getUserDiskPath() / "sms.db";
std::filesystem::remove(contactsPath);
std::filesystem::remove(smsPath);
SmsDB smsDB(smsPath.c_str());
REQUIRE(smsDB.isInitialized());
ContactsDB contactsDB(contactsPath.c_str());
REQUIRE(contactsDB.isInitialized());
const uint32_t dateTest = 123456789;
const char *snippetTest = "Test snippet";
const char *snippetTest2 = "Test snippet2";
const SMSType typeTest = SMSType ::UNKNOWN;
const uint32_t contactIDTest = 100;
ThreadRecordInterface threadRecordInterface1(&smsDB, &contactsDB);
ThreadRecord recordIN;
recordIN.date = dateTest;
recordIN.snippet = snippetTest;
recordIN.type = typeTest;
recordIN.contactID = contactIDTest;
// Add 2 records
REQUIRE(threadRecordInterface1.Add(recordIN));
REQUIRE(threadRecordInterface1.Add(recordIN));
SECTION("isUnread")
{
REQUIRE_FALSE(recordIN.isUnread());
recordIN.unreadMsgCount = 10;
REQUIRE(recordIN.isUnread());
}
SECTION("Get Count")
{
recordIN.unreadMsgCount = 10;
REQUIRE(threadRecordInterface1.Add(recordIN));
REQUIRE(threadRecordInterface1.GetCount() == 3);
REQUIRE(threadRecordInterface1.GetCount(EntryState::ALL) == 3);
REQUIRE(threadRecordInterface1.GetCount(EntryState::READ) == 2);
REQUIRE(threadRecordInterface1.GetCount(EntryState::UNREAD) == 1);
}
SECTION("Get all available records")
{
auto records = threadRecordInterface1.GetLimitOffset(0, 100);
REQUIRE((*records).size() == 2);
// Check if fetched records contain valid data
for (const auto &w : *records) {
REQUIRE(w.date == dateTest);
REQUIRE(w.snippet == snippetTest);
REQUIRE(w.type == typeTest);
REQUIRE(w.contactID == contactIDTest);
}
}
SECTION("Get all available records with query")
{
auto query = std::make_shared<db::query::ThreadsGet>(0, 100);
auto ret = threadRecordInterface1.runQuery(query);
auto result = dynamic_cast<db::query::ThreadsGetResults *>(ret.get());
REQUIRE(result != nullptr);
auto results = result->getResults();
REQUIRE(results.size() == 2);
// Check if fetched records contain valid data
for (const auto &w : results) {
REQUIRE(w.date == dateTest);
REQUIRE(w.snippet == snippetTest);
REQUIRE(w.type == typeTest);
REQUIRE(w.contactID == contactIDTest);
}
}
SECTION("Get all available records by specified thread ID and check for invalid data")
{
auto records = threadRecordInterface1.GetLimitOffsetByField(
0, 100, ThreadRecordField ::ContactID, std::to_string(contactIDTest).c_str());
REQUIRE((*records).size() == 2);
for (const auto &w : *records) {
REQUIRE(w.date == dateTest);
REQUIRE(w.snippet == snippetTest);
REQUIRE(w.type == typeTest);
REQUIRE(w.contactID == contactIDTest);
}
}
SECTION("Get record by id with query")
{
auto query = std::make_shared<db::query::ThreadGetByID>(1);
auto ret = threadRecordInterface1.runQuery(query);
auto result = dynamic_cast<db::query::ThreadGetByIDResult *>(ret.get());
REQUIRE(result->getRecord().has_value());
}
SECTION("Get record by contact id")
{
auto query = std::make_shared<db::query::ThreadGetByContactID>(contactIDTest);
auto ret = threadRecordInterface1.runQuery(query);
auto result = dynamic_cast<db::query::ThreadGetByContactIDResult *>(ret.get());
REQUIRE(result->getRecord().has_value());
REQUIRE(result->getRecord()->contactID == contactIDTest);
}
SECTION("Remove records one by one")
{
REQUIRE(threadRecordInterface1.RemoveByID(1));
REQUIRE(threadRecordInterface1.RemoveByID(2));
// SMS database should not contain any records
REQUIRE(threadRecordInterface1.GetCount() == 0);
}
SECTION("Remove records with query")
{
auto query1 = std::make_shared<db::query::ThreadRemove>(1);
auto ret1 = threadRecordInterface1.runQuery(query1);
auto result1 = dynamic_cast<db::query::ThreadRemoveResult *>(ret1.get());
REQUIRE(result1->success());
auto query2 = std::make_shared<db::query::ThreadRemove>(2);
auto ret2 = threadRecordInterface1.runQuery(query2);
auto result2 = dynamic_cast<db::query::ThreadRemoveResult *>(ret2.get());
REQUIRE(result2->success());
// SMS database should not contain any records
REQUIRE(threadRecordInterface1.GetCount() == 0);
}
SECTION("Test updating record")
{
// REQUIRE(threadRecordInterface1.Add(recordIN));
recordIN.ID = 1;
recordIN.snippet = snippetTest2;
REQUIRE(threadRecordInterface1.Update(recordIN));
auto record = threadRecordInterface1.GetByID(1);
REQUIRE(record.isValid());
REQUIRE(record.snippet == snippetTest2);
}
SECTION("Mark as read / unread")
{
recordIN.unreadMsgCount = 10;
REQUIRE(threadRecordInterface1.Add(recordIN));
auto rec = threadRecordInterface1.GetByID(3);
REQUIRE(rec.isUnread());
{
auto query = std::make_shared<db::query::MarkAsRead>(3, db::query::MarkAsRead::Read::True);
auto ret = threadRecordInterface1.runQuery(query);
auto result = dynamic_cast<db::query::MarkAsReadResult *>(ret.get());
REQUIRE(result != nullptr);
REQUIRE(result->getResult());
rec = threadRecordInterface1.GetByID(3);
REQUIRE_FALSE(rec.isUnread());
}
{
auto query = std::make_shared<db::query::MarkAsRead>(3, db::query::MarkAsRead::Read::False);
auto ret = threadRecordInterface1.runQuery(query);
auto result = dynamic_cast<db::query::MarkAsReadResult *>(ret.get());
REQUIRE(result != nullptr);
REQUIRE(result->getResult());
rec = threadRecordInterface1.GetByID(3);
REQUIRE(rec.isUnread());
}
}
SECTION("SMS search")
{
const utils::PhoneNumber phoneNumber("+48600123456", utils::country::Id::UNKNOWN);
const std::string lastSmsBody = "Ola";
SMSRecordInterface smsRecInterface(&smsDB, &contactsDB);
SMSRecord recordIN;
recordIN.date = 123456789;
recordIN.dateSent = 987654321;
recordIN.errorCode = 0;
recordIN.number = phoneNumber.getView();
recordIN.body = "Ala";
recordIN.type = SMSType ::DRAFT;
REQUIRE(smsRecInterface.Add(recordIN));
recordIN.body = lastSmsBody;
REQUIRE(smsRecInterface.Add(recordIN));
{
auto query = std::make_shared<db::query::ThreadsSearchForList>("A", 0, 10);
auto ret = threadRecordInterface1.runQuery(query);
auto result = dynamic_cast<db::query::ThreadsSearchResultForList *>(ret.get());
REQUIRE(result != nullptr);
auto results = result->getResults();
REQUIRE(results.size() == 2);
}
{
auto query = std::make_shared<db::query::ThreadsSearchForList>("O", 0, 10);
auto ret = threadRecordInterface1.runQuery(query);
auto result = dynamic_cast<db::query::ThreadsSearchResultForList *>(ret.get());
REQUIRE(result != nullptr);
auto results = result->getResults();
REQUIRE(results.size() == 1);
}
SECTION("Get last SMS by thread id")
{
auto getThreadQuery = std::make_shared<db::query::ThreadGetByNumber>(phoneNumber.getView());
auto getThreadRet = threadRecordInterface1.runQuery(getThreadQuery);
auto getThreatResult = dynamic_cast<db::query::ThreadGetByNumberResult *>(getThreadRet.get());
REQUIRE(getThreatResult != nullptr);
auto threadRec = getThreatResult->getThread();
REQUIRE(threadRec.isValid());
auto getLastQuery = std::make_shared<db::query::SMSGetLastByThreadID>(threadRec.ID);
auto getLastRet = smsRecInterface.runQuery(getLastQuery);
auto getLastResult = dynamic_cast<db::query::SMSGetLastByThreadIDResult *>(getLastRet.get());
REQUIRE(getLastResult != nullptr);
auto smsRec = getLastResult->record;
REQUIRE(smsRec.has_value());
REQUIRE(smsRec->body == lastSmsBody);
}
}
Database::deinitialize();
}