~aleteoryx/muditaos

6711e02bad8f1925968e7018c808d9d681b5c6ee — jimmorrisson 5 years ago 1520a9a
[EGD-4446] Change: new filesystem handling implementation in module db. (#1052)

Due to vfs deprecation there is need to remove all vfs calls from code. This PR covers module database. It also contains minor fixes in module-db.
54 files changed, 349 insertions(+), 286 deletions(-)

M module-db/Database/Database.cpp
M module-db/Database/Database.hpp
M module-db/Database/DatabaseInitializer.cpp
M module-db/Database/DatabaseInitializer.hpp
M module-db/Database/sqlite3vfs.cpp
M module-db/Databases/AlarmsDB.cpp
M module-db/Databases/AlarmsDB.hpp
M module-db/Databases/CalllogDB.cpp
M module-db/Databases/CalllogDB.hpp
M module-db/Databases/ContactsDB.cpp
M module-db/Databases/ContactsDB.hpp
M module-db/Databases/CountryCodesDB.cpp
M module-db/Databases/CountryCodesDB.hpp
M module-db/Databases/EventsDB.cpp
M module-db/Databases/EventsDB.hpp
M module-db/Databases/NotesDB.cpp
M module-db/Databases/NotesDB.hpp
M module-db/Databases/NotificationsDB.cpp
M module-db/Databases/NotificationsDB.hpp
M module-db/Databases/SmsDB.cpp
M module-db/Databases/SmsDB.hpp
M module-db/Interface/NotificationsRecord.cpp
M module-db/Interface/NotificationsRecord.hpp
M module-db/Tables/NotificationsTable.hpp
M module-db/tests/AlarmsRecord_tests.cpp
M module-db/tests/AlarmsTable_tests.cpp
M module-db/tests/CMakeLists.txt
M module-db/tests/CalllogRecord_tests.cpp
M module-db/tests/CalllogTable_tests.cpp
M module-db/tests/ContactGroups_tests.cpp
M module-db/tests/ContactsAddressTable_tests.cpp
M module-db/tests/ContactsNameTable_tests.cpp
M module-db/tests/ContactsNumberTable_tests.cpp
M module-db/tests/ContactsRecord_tests.cpp
M module-db/tests/ContactsRingtonesTable_tests.cpp
M module-db/tests/ContactsTable_tests.cpp
M module-db/tests/EventsRecord_tests.cpp
M module-db/tests/EventsTable_tests.cpp
M module-db/tests/NotesRecord_tests.cpp
M module-db/tests/NotesTable_tests.cpp
M module-db/tests/NotificationsRecord_tests.cpp
M module-db/tests/NotificationsTable_tests.cpp
M module-db/tests/QueryInterface.cpp
M module-db/tests/SMSRecord_tests.cpp
M module-db/tests/SMSTable_tests.cpp
M module-db/tests/SMSTemplateRecord_tests.cpp
M module-db/tests/SMSTemplateTable_tests.cpp
M module-db/tests/ThreadRecord_tests.cpp
M module-db/tests/ThreadsTable_tests.cpp
M module-db/tests/unittest.cpp
M module-services/service-db/ServiceDB.cpp
M module-utils/Utils.hpp
M module-utils/i18n/i18n.hpp
M module-utils/test/unittest_utils.cpp
M module-db/Database/Database.cpp => module-db/Database/Database.cpp +4 -3
@@ 5,9 5,9 @@
#include "DatabaseInitializer.hpp"

#include "log/log.hpp"
#include "vfs.hpp"
#include <assert.h>
#include <memory>
#include <purefs/filesystem_paths.hpp>

/* Declarations *********************/
extern sqlite3_vfs *sqlite3_ecophonevfs(void);


@@ 76,8 76,9 @@ Database::Database(const char *name)
    pragmaQuery("PRAGMA integrity_check;");
    pragmaQuery("PRAGMA locking_mode=EXCLUSIVE");

    LOG_INFO("running scripts: %s", USER_PATH("db"));
    isInitialized_ = initializer->run(USER_PATH("db"), INIT_SCRIPTS_EXT);
    const auto filePath = (purefs::dir::getUserDiskPath() / "db");
    LOG_INFO("running scripts: %s", filePath.c_str());
    isInitialized_ = initializer->run(filePath.c_str(), INIT_SCRIPTS_EXT);
}

Database::~Database()

M module-db/Database/Database.hpp => module-db/Database/Database.hpp +0 -1
@@ 7,7 7,6 @@

#include "QueryResult.hpp"

#include <vfs.hpp>
#include <memory>
#include <set>


M module-db/Database/DatabaseInitializer.cpp => module-db/Database/DatabaseInitializer.cpp +57 -29
@@ 3,18 3,21 @@

#include "DatabaseInitializer.hpp"

#include <vfs.hpp>
#include <algorithm>
#include <cstdio>
#include <memory>
#include <set>
#include <string>
#include <log/log.hpp>

DatabaseInitializer::DatabaseInitializer(Database *db) : db(db)
{}

bool DatabaseInitializer::run(fs::path path, std::string ext)
bool DatabaseInitializer::run(std::filesystem::path path, std::string ext)
{
    // Database name is database file path, need to strip off all filesystem related stuff(path, extension)
    fs::path dbpath    = db->getName();
    std::string dbname = dbpath.filename().replace_extension();
    std::filesystem::path dbpath = db->getName();
    std::string dbname           = dbpath.filename().replace_extension();

    auto files = listFiles(path, dbname, ext);
    for (auto file : files) {


@@ 28,30 31,54 @@ bool DatabaseInitializer::run(fs::path path, std::string ext)
    return true;
}

std::vector<std::string> DatabaseInitializer::readCommands(fs::path filePath)
std::string DatabaseInitializer::readContent(const char *filename) const noexcept
{
    ScopedFile file(filePath, "r");
    std::unique_ptr<char[]> fcontent;
    long fsize = 0;

    std::string line;
    std::string currentStatement;
    std::vector<std::string> statements;
    auto fp = std::fopen(filename, "r");
    if (fp) {
        std::fseek(fp, 0, SEEK_END);
        fsize = std::ftell(fp);
        std::rewind(fp);

    while (!vfs.eof(file.get())) {
        line = vfs.getline(file.get());
        fcontent = std::make_unique<char[]>(fsize + 1);

        if (line.empty() || starts_with(line, std::string("--"))) {
            continue;
        }
        std::fread(fcontent.get(), 1, fsize, fp);

        std::fclose(fp);
    }

    return std::string(fcontent.get());
}

        if (ends_with(line, std::string(";"))) {
            statements.push_back(currentStatement + line);
            currentStatement.clear();
            continue;
std::vector<std::string> DatabaseInitializer::readCommands(std::filesystem::path filePath)
{
    auto fileContent = readContent(filePath.c_str());
    std::string currentStatement{};
    std::vector<std::string> statements{};

    std::string line{};
    for (auto &c : fileContent) {
        if (c != '\n') {
            line += c;
        }
        else {
            if (line.empty() || starts_with(line, std::string("--"))) {
                line.clear();
                continue;
            }
            if (ends_with(line, std::string(";"))) {
                statements.push_back(currentStatement + line);
                currentStatement.clear();
                line.clear();
                continue;
            }
            currentStatement += line;

        currentStatement += line;
            line.clear();
        }
    }

    return statements;
}



@@ 64,27 91,28 @@ std::array<std::string, 3> DatabaseInitializer::splitFilename(std::string filena
    return {name, prefix, postfix};
}

std::vector<fs::path> DatabaseInitializer::listFiles(fs::path path, std::string prefix, std::string ext)
std::vector<std::filesystem::path> DatabaseInitializer::listFiles(std::filesystem::path path,
                                                                  std::string prefix,
                                                                  std::string ext)
{
    std::set<std::pair<int, fs::path>> orderedFiles;
    auto dirList = vfs.listdir(path.c_str(), ext);
    for (vfs::DirectoryEntry ent : dirList) {
        if (ent.attributes != vfs::FileAttributes::Directory) {
    std::set<std::pair<int, std::filesystem::path>> orderedFiles;
    for (const auto &entry : std::filesystem::directory_iterator(path)) {
        if (!entry.is_directory() && entry.path().has_filename()) {
            try {
                auto parts      = splitFilename(ent.fileName);
                auto parts      = splitFilename(entry.path().filename().string());
                auto filePrefix = parts[1];
                if (filePrefix == prefix) {
                    auto num = std::stoi(parts[2]);
                    orderedFiles.insert({num, path / ent.fileName});
                    orderedFiles.insert({num, entry.path()});
                }
            }
            catch (std::invalid_argument &e) {
                LOG_INFO("Ignoring file: %s", ent.fileName.c_str());
                LOG_INFO("Ignoring file: %s", entry.path().c_str());
            }
        }
    }

    std::vector<fs::path> files;
    std::vector<std::filesystem::path> files;
    std::for_each(orderedFiles.begin(), orderedFiles.end(), [&](auto item) { files.push_back(item.second); });
    return files;
}

M module-db/Database/DatabaseInitializer.hpp => module-db/Database/DatabaseInitializer.hpp +11 -7
@@ 4,6 4,8 @@
#pragma once

#include "Database.hpp"
#include <fstream>
#include <filesystem>

namespace
{


@@ 28,32 30,33 @@ class DatabaseInitializer
      public:
        ScopedFile(std::string path, std::string mode)
        {
            file = vfs.fopen(path.c_str(), mode.c_str());
            file = std::fopen(path.c_str(), mode.c_str());
        }

        ~ScopedFile()
        {
            vfs.fclose(file);
            std::fclose(file);
        }

        [[nodiscard]] vfs::FILE *get() const
        [[nodiscard]] std::FILE *get() const
        {
            return file;
        }

      private:
        vfs::FILE *file = nullptr;
        std::FILE *file = nullptr;
    };

  public:
    DatabaseInitializer(Database *db);
    ~DatabaseInitializer() = default;

    auto run(fs::path path, std::string ext = "sql") -> bool;
    auto run(std::filesystem::path path, std::string ext = "sql") -> bool;

    auto readCommands(fs::path filePath) -> std::vector<std::string>;
    auto readCommands(std::filesystem::path filePath) -> std::vector<std::string>;

    auto listFiles(fs::path path, std::string prefix, std::string ext) -> std::vector<fs::path>;
    auto listFiles(std::filesystem::path path, std::string prefix, std::string ext)
        -> std::vector<std::filesystem::path>;

    auto executeOnDb(const std::vector<std::string> statements) -> bool;



@@ 65,6 68,7 @@ class DatabaseInitializer
     *  [2] - num
     */
    auto splitFilename(std::string filename) -> std::array<std::string, 3>;
    std::string readContent(const char *filename) const noexcept;

    Database *db = nullptr;
};

M module-db/Database/sqlite3vfs.cpp => module-db/Database/sqlite3vfs.cpp +26 -25
@@ 122,9 122,11 @@

#include "FreeRTOS.h"
#include "task.h"
#include "vfs.hpp"
#include "config.h"

#include <Utils.hpp>
#include <dirent.h>

//#include <log/log.hpp> //left for future debug

/*


@@ 149,7 151,7 @@ typedef struct EcophoneFile EcophoneFile;
struct EcophoneFile
{
    sqlite3_file base; /* Base class. Must be first. */
    vfs::FILE *fd;     /* File descriptor */
    std::FILE *fd;     /* File descriptor */

    char *aBuffer;             /* Pointer to malloc'd buffer */
    int nBuffer;               /* Valid bytes of data in zBuffer */


@@ 167,15 169,15 @@ static int ecophoneDirectWrite(EcophoneFile *p,   /* File handle */
)
{
    size_t nWrite; /* Return value from write() */
    const auto fileSize = vfs.filelength(p->fd);
    const auto fileSize = utils::filesystem::filelength(p->fd);
    // vfs_fseek doesn't like offset to be > file size
    if (iOfst < fileSize) {
        if (vfs.fseek(p->fd, iOfst, SEEK_SET) != 0) {
        if (std::fseek(p->fd, iOfst, SEEK_SET) != 0) {
            return SQLITE_IOERR_WRITE;
        }
    }
    else {
        if (vfs.fseek(p->fd, fileSize, SEEK_SET) != 0) {
        if (std::fseek(p->fd, fileSize, SEEK_SET) != 0) {
            return SQLITE_IOERR_WRITE;
        }
        // Zero fill if outside the buffer


@@ 198,7 200,7 @@ static int ecophoneDirectWrite(EcophoneFile *p,   /* File handle */
                    bytesToWrite = zerobuf_size;
                }
            }
            auto ret = vfs.fwrite(zero_buf.get(), sizeof(char), bytesToWrite, p->fd);
            auto ret = std::fwrite(zero_buf.get(), sizeof(char), bytesToWrite, p->fd);
            if (ret != bytesToWrite) {
                return SQLITE_IOERR_WRITE;
            }


@@ 206,11 208,11 @@ static int ecophoneDirectWrite(EcophoneFile *p,   /* File handle */
        }
    }

    nWrite = vfs.fwrite(zBuf, 1, iAmt, p->fd);
    nWrite = std::fwrite(zBuf, 1, iAmt, p->fd);
    if ((int)nWrite != iAmt) {
        return SQLITE_IOERR_WRITE;
    }
    if (ff_fflush(p->fd) != 0) {
    if (std::fflush(p->fd) != 0) {
        return SQLITE_IOERR_WRITE;
    }
    return SQLITE_OK;


@@ 241,7 243,7 @@ static int ecophoneClose(sqlite3_file *pFile)
    rc              = ecophoneFlushBuffer(p);
    sqlite3_free(p->aBuffer);

    vfs.fclose(p->fd);
    std::fclose(p->fd);
    return rc;
}



@@ 265,7 267,7 @@ static int ecophoneRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 
        return rc;
    }

    auto fileSize = vfs.filelength(p->fd);
    auto fileSize = utils::filesystem::filelength(p->fd);

    if (p->fd != nullptr) {
        if (iOfst >= fileSize) {


@@ 273,11 275,11 @@ static int ecophoneRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 
        }
    }

    if (vfs.fseek(p->fd, iOfst, SEEK_SET) != 0) {
    if (std::fseek(p->fd, iOfst, SEEK_SET) != 0) {
        return SQLITE_IOERR_READ;
    }

    nRead = vfs.fread(zBuf, 1, iAmt, p->fd);
    nRead = std::fread(zBuf, 1, iAmt, p->fd);

    if (nRead == iAmt) {
        return SQLITE_OK;


@@ 390,7 392,7 @@ static int ecophoneFileSize(sqlite3_file *pFile, sqlite_int64 *pSize)
        return rc;
    }

    *pSize = vfs.filelength(p->fd);
    *pSize = utils::filesystem::filelength(p->fd);

    return SQLITE_OK;
}


@@ 456,7 458,7 @@ static int ecophoneDeviceCharacteristics(sqlite3_file *pFile)
 */
static int ecophoneAccess(sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut)
{
    vfs::FILE *fd;
    std::FILE *fd;
    UNUSED(pVfs);

    assert(flags == SQLITE_ACCESS_EXISTS       /* access(zPath, F_OK) */


@@ 464,11 466,11 @@ static int ecophoneAccess(sqlite3_vfs *pVfs, const char *zPath, int flags, int *
           || flags == SQLITE_ACCESS_READWRITE /* access(zPath, R_OK|W_OK) */
    );

    fd = vfs.fopen(zPath, (const char *)"r");
    fd = std::fopen(zPath, "r");
    if (fd != NULL) {
        if (pResOut)
            *pResOut = flags;
        vfs.fclose(fd);
        std::fclose(fd);
    }
    else if (pResOut)
        *pResOut = 0;


@@ 528,14 530,14 @@ static int ecophoneOpen(sqlite3_vfs *pVfs,   /* VFS */
    else if ((flags & SQLITE_OPEN_READWRITE) && (flags & SQLITE_OPEN_CREATE)) {

        // check if database specified exists
        p->fd = vfs.fopen(zName, "r");
        p->fd = std::fopen(zName, "r");
        if (p->fd == nullptr) {
            // database doesn't exist, create new one with read&write permissions
            oflags = "w+";
        }
        else {
            // database exists, open it with read&write permissions
            vfs.fclose(p->fd);
            std::fclose(p->fd);
            oflags = "r+";
        }
    }


@@ 543,7 545,7 @@ static int ecophoneOpen(sqlite3_vfs *pVfs,   /* VFS */
        oflags = "r+";
    }

    p->fd = vfs.fopen(zName, oflags.c_str());
    p->fd = std::fopen(zName, oflags.c_str());
    if (p->fd == nullptr) {
        sqlite3_free(aBuf);
        return SQLITE_CANTOPEN;


@@ 565,14 567,13 @@ static int ecophoneOpen(sqlite3_vfs *pVfs,   /* VFS */
static int ecophoneDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync)
{
    UNUSED(pVfs);
    int rc; /* Return code */
    int rc = std::filesystem::remove_all(zPath); /* Return code */

    rc = vfs.remove(zPath);
    if (rc != 0 /*&& errno==ENOENT*/)
    if (rc != 0)
        return SQLITE_OK;

    if (rc == 0 && dirSync) {
        vfs::FILE *dfd;             /* File descriptor open on directory */
        DIR *dfd;                   /* File descriptor open on directory */
        int i;                      /* Iterator variable */
        char zDir[MAXPATHNAME + 1]; /* Name of directory containing file zPath */



@@ 584,13 585,13 @@ static int ecophoneDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync)
        zDir[i] = '\0';

        /* Open a file-descriptor on the directory. Sync. Close. */
        dfd = vfs.fopen(zDir, "D");
        dfd = opendir(zDir);
        if (dfd == NULL) {
            rc = -1;
        }
        else {
            rc = SQLITE_OK;
            vfs.fclose(dfd);
            closedir(dfd);
        }
    }
    return (rc == 0 ? SQLITE_OK : SQLITE_IOERR_DELETE);

M module-db/Databases/AlarmsDB.cpp => module-db/Databases/AlarmsDB.cpp +1 -4
@@ 1,10 1,7 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <vfs.hpp>
#include "AlarmsDB.hpp"

const char *AlarmsDB::dbName = USER_PATH("alarms.db");

AlarmsDB::AlarmsDB() : Database(dbName), alarms(this), alarmStatuses(this)
AlarmsDB::AlarmsDB(const char *name) : Database(name), alarms(this), alarmStatuses(this)
{}

M module-db/Databases/AlarmsDB.hpp => module-db/Databases/AlarmsDB.hpp +1 -9
@@ 9,17 9,9 @@
class AlarmsDB : public Database
{
  public:
    AlarmsDB();
    AlarmsDB(const char *name);
    ~AlarmsDB() = default;

    AlarmsTable alarms;
    AlarmsStatusTable alarmStatuses;

    static const char *GetDBName()
    {
        return dbName;
    }

  private:
    static const char *dbName;
};

M module-db/Databases/CalllogDB.cpp => module-db/Databases/CalllogDB.cpp +1 -4
@@ 1,10 1,7 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <vfs.hpp>
#include "CalllogDB.hpp"

const char *CalllogDB::dbName = USER_PATH("calllog.db");

CalllogDB::CalllogDB() : Database(dbName), calls(this)
CalllogDB::CalllogDB(const char *name) : Database(name), calls(this)
{}

M module-db/Databases/CalllogDB.hpp => module-db/Databases/CalllogDB.hpp +1 -9
@@ 9,16 9,8 @@
class CalllogDB : public Database
{
  public:
    CalllogDB();
    CalllogDB(const char *name);
    ~CalllogDB() = default;

    CalllogTable calls;

    static const char *GetDBName()
    {
        return dbName;
    }

  private:
    static const char *dbName;
};

M module-db/Databases/ContactsDB.cpp => module-db/Databases/ContactsDB.cpp +2 -5
@@ 1,18 1,15 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <vfs.hpp>
#include "ContactsDB.hpp"

const char *ContactsDB::dbName = USER_PATH("contacts.db");

uint32_t ContactsDB::favouritesId = 0;
uint32_t ContactsDB::iceId        = 0;
uint32_t ContactsDB::blockedId    = 0;
uint32_t ContactsDB::temporaryId  = 0;

ContactsDB::ContactsDB()
    : Database(dbName), contacts(this), name(this), number(this), ringtones(this), address(this), groups(this)
ContactsDB::ContactsDB(const char *name)
    : Database(name), contacts(this), name(this), number(this), ringtones(this), address(this), groups(this)
{

    if (favouritesId == 0) {

M module-db/Databases/ContactsDB.hpp => module-db/Databases/ContactsDB.hpp +1 -7
@@ 14,14 14,9 @@
class ContactsDB : public Database
{
  public:
    ContactsDB();
    ContactsDB(const char *name);
    ~ContactsDB() = default;

    static const char *GetDBName()
    {
        return dbName;
    }

    ContactsTable contacts;
    ContactsNameTable name;
    ContactsNumberTable number;


@@ 47,7 42,6 @@ class ContactsDB : public Database
    }

  private:
    static const char *dbName;
    static uint32_t favouritesId;
    static uint32_t iceId;
    static uint32_t blockedId;

M module-db/Databases/CountryCodesDB.cpp => module-db/Databases/CountryCodesDB.cpp +1 -3
@@ 3,9 3,7 @@

#include "CountryCodesDB.hpp"

const char *CountryCodesDB::dbName = "country-codes.db";

CountryCodesDB::CountryCodesDB() : Database(dbName), countryCodes(this)
CountryCodesDB::CountryCodesDB(const char *name) : Database(name), countryCodes(this)
{
    if (countryCodes.create() == false)
        return;

M module-db/Databases/CountryCodesDB.hpp => module-db/Databases/CountryCodesDB.hpp +1 -9
@@ 8,16 8,8 @@
class CountryCodesDB : public Database
{
  public:
    CountryCodesDB();
    CountryCodesDB(const char *name);
    ~CountryCodesDB();

    static const char *GetDBName()
    {
        return dbName;
    }

    CountryCodesTable countryCodes;

  private:
    static const char *dbName;
};

M module-db/Databases/EventsDB.cpp => module-db/Databases/EventsDB.cpp +1 -5
@@ 3,11 3,7 @@

#include "EventsDB.hpp"

#include <vfs.hpp>

const char *EventsDB::dbName = USER_PATH("events.db");

EventsDB::EventsDB() : Database(dbName), events(this)
EventsDB::EventsDB(const char *name) : Database(name), events(this)
{
    if (events.create() == false) {
        return;

M module-db/Databases/EventsDB.hpp => module-db/Databases/EventsDB.hpp +1 -9
@@ 9,16 9,8 @@
class EventsDB : public Database
{
  public:
    EventsDB();
    EventsDB(const char *name);
    ~EventsDB() override = default;

    EventsTable events;

    static const char *GetDBName()
    {
        return dbName;
    }

  private:
    static const char *dbName;
};

M module-db/Databases/NotesDB.cpp => module-db/Databases/NotesDB.cpp +1 -4
@@ 1,10 1,7 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <vfs.hpp>
#include "NotesDB.hpp"

const char *NotesDB::dbName = USER_PATH("notes.db");

NotesDB::NotesDB() : Database(dbName), notes(this)
NotesDB::NotesDB(const char *name) : Database(name), notes(this)
{}

M module-db/Databases/NotesDB.hpp => module-db/Databases/NotesDB.hpp +1 -9
@@ 9,16 9,8 @@
class NotesDB : public Database
{
  public:
    NotesDB();
    NotesDB(const char *name);
    ~NotesDB() = default;

    NotesTable notes;

    static const char *GetDBName()
    {
        return dbName;
    }

  private:
    static const char *dbName;
};

M module-db/Databases/NotificationsDB.cpp => module-db/Databases/NotificationsDB.cpp +1 -5
@@ 3,9 3,5 @@

#include "NotificationsDB.hpp"

#include <vfs.hpp>

const char *NotificationsDB::dbName = USER_PATH("notifications.db");

NotificationsDB::NotificationsDB() : Database(dbName), notifications(this)
NotificationsDB::NotificationsDB(const char *name) : Database(name), notifications(this)
{}

M module-db/Databases/NotificationsDB.hpp => module-db/Databases/NotificationsDB.hpp +1 -9
@@ 9,16 9,8 @@
class NotificationsDB : public Database
{
  public:
    NotificationsDB();
    NotificationsDB(const char *name);
    virtual ~NotificationsDB() = default;

    NotificationsTable notifications;

    static const char *GetDBName()
    {
        return dbName;
    }

  private:
    static const char *dbName;
};

M module-db/Databases/SmsDB.cpp => module-db/Databases/SmsDB.cpp +1 -4
@@ 1,10 1,7 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <vfs.hpp>
#include "SmsDB.hpp"

const char *SmsDB::dbName = USER_PATH("sms.db");

SmsDB::SmsDB() : Database(dbName), sms(this), threads(this), templates(this)
SmsDB::SmsDB(const char *name) : Database(name), sms(this), threads(this), templates(this)
{}

M module-db/Databases/SmsDB.hpp => module-db/Databases/SmsDB.hpp +1 -9
@@ 11,18 11,10 @@
class SmsDB : public Database
{
  public:
    SmsDB();
    SmsDB(const char *name);
    ~SmsDB() = default;

    SMSTable sms;
    ThreadsTable threads;
    SMSTemplateTable templates;

    static const char *GetDBName()
    {
        return dbName;
    }

  private:
    static const char *dbName;
};

M module-db/Interface/NotificationsRecord.cpp => module-db/Interface/NotificationsRecord.cpp +4 -3
@@ 79,7 79,7 @@ std::unique_ptr<std::vector<NotificationsRecord>> NotificationsRecordInterface::
    auto records = std::make_unique<std::vector<NotificationsRecord>>();

    for (auto &r : rows) {
        records->push_back(r);
        records->push_back(NotificationsRecord{r});
    }

    return records;


@@ 112,7 112,7 @@ bool NotificationsRecordInterface::RemoveByField(NotificationsRecordField field,

NotificationsRecord NotificationsRecordInterface::GetByID(uint32_t id)
{
    return notificationsDb->notifications.getById(id);
    return NotificationsRecord{notificationsDb->notifications.getById(id)};
}

uint32_t NotificationsRecordInterface::GetCount()


@@ 126,7 126,8 @@ NotificationsRecord NotificationsRecordInterface::GetByKey(NotificationsRecord::
        return NotificationsRecord();
    }

    return notificationsDb->notifications.GetByKey(static_cast<uint32_t>(key));
    NotificationsTableRow notificationsTableRow = notificationsDb->notifications.GetByKey(static_cast<uint32_t>(key));
    return NotificationsRecord{notificationsTableRow};
}

std::unique_ptr<db::QueryResult> NotificationsRecordInterface::runQuery(std::shared_ptr<db::Query> query)

M module-db/Interface/NotificationsRecord.hpp => module-db/Interface/NotificationsRecord.hpp +2 -2
@@ 42,7 42,7 @@ struct NotificationsRecord : public Record

    NotificationsRecord()  = default;
    ~NotificationsRecord() = default;
    NotificationsRecord(const NotificationsTableRow &tableRow);
    explicit NotificationsRecord(const NotificationsTableRow &tableRow);

    bool isValidRecord() const;
    bool gotValidKey() const;


@@ 58,7 58,7 @@ enum class NotificationsRecordField
class NotificationsRecordInterface : public RecordInterface<NotificationsRecord, NotificationsRecordField>
{
  public:
    NotificationsRecordInterface(NotificationsDB *notificationsDb);
    explicit NotificationsRecordInterface(NotificationsDB *notificationsDb);
    virtual ~NotificationsRecordInterface() = default;

    bool Add(const NotificationsRecord &rec) override final;

M module-db/Tables/NotificationsTable.hpp => module-db/Tables/NotificationsTable.hpp +1 -1
@@ 23,7 23,7 @@ enum class NotificationsTableFields
class NotificationsTable : public Table<NotificationsTableRow, NotificationsTableFields>
{
  public:
    NotificationsTable(Database *db);
    explicit NotificationsTable(Database *db);
    virtual ~NotificationsTable() = default;

    bool create() override final;

M module-db/tests/AlarmsRecord_tests.cpp => module-db/tests/AlarmsRecord_tests.cpp +4 -2
@@ 20,14 20,16 @@
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Alarms Record tests")
{
    Database::initialize();

    vfs.remove(AlarmsDB::GetDBName());
    const auto alarmsPath = (purefs::dir::getUserDiskPath() / "alarms.db").c_str();
    std::filesystem::remove(alarmsPath);

    auto alarmsDB = AlarmsDB();
    auto alarmsDB = AlarmsDB(alarmsPath);
    REQUIRE(alarmsDB.isInitialized());

    SECTION("Default Constructor")

M module-db/tests/AlarmsTable_tests.cpp => module-db/tests/AlarmsTable_tests.cpp +6 -3
@@ 1,7 1,8 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "vfs.hpp"
#include <vfs.hpp>
#include <filesystem>

#include <catch2/catch.hpp>



@@ 14,14 15,16 @@
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Alarms Table tests")
{
    Database::initialize();

    vfs.remove(AlarmsDB::GetDBName());
    const auto alarmsPath = (purefs::dir::getUserDiskPath() / "alarms.db").c_str();
    std::filesystem::remove(alarmsPath);

    AlarmsDB alarmsDb;
    AlarmsDB alarmsDb(alarmsPath);
    REQUIRE(alarmsDb.isInitialized());

    auto &alarmsTbl = alarmsDb.alarms;

M module-db/tests/CMakeLists.txt => module-db/tests/CMakeLists.txt +1 -0
@@ 35,4 35,5 @@ add_catch2_executable(
        
    LIBS
        module-db
        module-vfs
)

M module-db/tests/CalllogRecord_tests.cpp => module-db/tests/CalllogRecord_tests.cpp +7 -4
@@ 14,16 14,19 @@
#include <string.h>
#include <algorithm>
#include <iostream>
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Calllog Record tests")
{
    Database::initialize();

    vfs.remove(CalllogDB::GetDBName());
    vfs.remove(ContactsDB::GetDBName());
    const auto callogPath   = (purefs::dir::getUserDiskPath() / "callog.db").c_str();
    const auto contactsPath = (purefs::dir::getUserDiskPath() / "contacts.db").c_str();
    std::filesystem::remove(callogPath);
    std::filesystem::remove(contactsPath);

    CalllogDB calllogDb;
    ContactsDB contactsDb;
    CalllogDB calllogDb(callogPath);
    ContactsDB contactsDb(contactsPath);

    REQUIRE(calllogDb.isInitialized());
    REQUIRE(contactsDb.isInitialized());

M module-db/tests/CalllogTable_tests.cpp => module-db/tests/CalllogTable_tests.cpp +5 -2
@@ 12,15 12,18 @@
#include <stdint.h>
#include <string>
#include <algorithm>
#include <filesystem>
#include <iostream>
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Calllog Table tests")
{
    Database::initialize();

    vfs.remove(CalllogDB::GetDBName());
    const auto callogPath = (purefs::dir::getUserDiskPath() / "callog.db").c_str();
    std::filesystem::remove(callogPath);

    CalllogDB calllogDb;
    CalllogDB calllogDb{callogPath};
    REQUIRE(calllogDb.isInitialized());

    auto &callsTbl = calllogDb.calls;

M module-db/tests/ContactGroups_tests.cpp => module-db/tests/ContactGroups_tests.cpp +5 -2
@@ 8,9 8,11 @@
#include <Tables/ContactsGroups.hpp>

#include <vfs.hpp>
#include <filesystem>

#include <iomanip>
#include <sstream>
#include <purefs/filesystem_paths.hpp>

namespace consts
{


@@ 26,8 28,9 @@ TEST_CASE("Contact Groups tests", "[Groups]")
{
    INFO("sqlite Init");
    Database::initialize();
    vfs.remove(ContactsDB::GetDBName());
    ContactsDB contactDb;
    const auto callogPath = (purefs::dir::getUserDiskPath() / "contacts.db").c_str();
    std::filesystem::remove(callogPath);
    ContactsDB contactDb{callogPath};
    INFO("contactDB init");
    REQUIRE(contactDb.isInitialized());
    ContactsGroupsTable contactGroupsTable = ContactsGroupsTable(&contactDb);

M module-db/tests/ContactsAddressTable_tests.cpp => module-db/tests/ContactsAddressTable_tests.cpp +6 -3
@@ 4,15 4,18 @@
#include <catch2/catch.hpp>

#include "Databases/ContactsDB.hpp"
#include "vfs.hpp"
#include <vfs.hpp>
#include <filesystem>
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Contacts address Table tests")
{
    Database::initialize();

    vfs.remove(ContactsDB::GetDBName());
    const auto callogPath = (purefs::dir::getUserDiskPath() / "contacts.db").c_str();
    std::filesystem::remove(callogPath);

    ContactsDB contactsdb;
    ContactsDB contactsdb{callogPath};
    REQUIRE(contactsdb.isInitialized());

    ContactsAddressTableRow testRow1 = {{.ID = DB_ID_NONE},

M module-db/tests/ContactsNameTable_tests.cpp => module-db/tests/ContactsNameTable_tests.cpp +4 -3
@@ 1,7 1,6 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "vfs.hpp"

#include <catch2/catch.hpp>



@@ 13,14 12,16 @@
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Contacts Name Table tests")
{
    Database::initialize();

    vfs.remove(ContactsDB::GetDBName());
    const auto contactsPath = (purefs::dir::getUserDiskPath() / "contacts.db").c_str();
    std::remove(contactsPath);

    ContactsDB contactsdb;
    ContactsDB contactsdb(contactsPath);
    REQUIRE(contactsdb.isInitialized());

    ContactsNameTableRow testRow1 = {

M module-db/tests/ContactsNumberTable_tests.cpp => module-db/tests/ContactsNumberTable_tests.cpp +6 -3
@@ 1,9 1,10 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "vfs.hpp"
#include <vfs.hpp>

#include <catch2/catch.hpp>
#include <filesystem>

#include "Database/Database.hpp"
#include "Databases/ContactsDB.hpp"


@@ 13,14 14,16 @@
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Contacts Number Table tests")
{
    Database::initialize();

    vfs.remove(ContactsDB::GetDBName());
    const auto contactsPath = (purefs::dir::getUserDiskPath() / "contacts.db").c_str();
    std::filesystem::remove(contactsPath);

    ContactsDB contactsdb;
    ContactsDB contactsdb{contactsPath};
    REQUIRE(contactsdb.isInitialized());

    ContactsNumberTableRow testRow1 = {

M module-db/tests/ContactsRecord_tests.cpp => module-db/tests/ContactsRecord_tests.cpp +7 -4
@@ 6,14 6,16 @@
#include "Interface/ContactRecord.hpp"
#include "module-utils/i18n/i18n.hpp"
#include "vfs.hpp"
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Contact Record db tests")
{
    Database::initialize();

    vfs.remove(ContactsDB::GetDBName());
    const auto contactsPath = (purefs::dir::getUserDiskPath() / "contacts.db").c_str();
    std::filesystem::remove(contactsPath);

    auto contactDB = std::make_unique<ContactsDB>();
    auto contactDB = std::make_unique<ContactsDB>(contactsPath);
    REQUIRE(contactDB->isInitialized());

    const char *primaryNameTest                   = "PrimaryNameTest";


@@ 259,9 261,10 @@ TEST_CASE("Test converting contact data to string")
TEST_CASE("Contact record numbers update")
{
    Database::initialize();
    vfs.remove(ContactsDB::GetDBName());
    const auto contactsPath = (purefs::dir::getUserDiskPath() / "contacts.db").c_str();
    std::filesystem::remove(contactsPath);

    auto contactDB = std::make_unique<ContactsDB>();
    auto contactDB = std::make_unique<ContactsDB>(contactsPath);
    REQUIRE(contactDB->isInitialized());

    auto records = ContactRecordInterface(contactDB.get());

M module-db/tests/ContactsRingtonesTable_tests.cpp => module-db/tests/ContactsRingtonesTable_tests.cpp +6 -3
@@ 1,7 1,7 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "vfs.hpp"
#include <vfs.hpp>

#include <catch2/catch.hpp>



@@ 9,18 9,21 @@
#include "Databases/ContactsDB.hpp"

#include <algorithm>
#include <filesystem>

#include <cstdint>
#include <cstdio>
#include <cstring>
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Contacts Ringtones Table tests")
{
    Database::initialize();

    vfs.remove(ContactsDB::GetDBName());
    const auto contactsPath = (purefs::dir::getUserDiskPath() / "contacts.db").c_str();
    std::filesystem::remove(contactsPath);

    ContactsDB contactsdb;
    ContactsDB contactsdb{contactsPath};
    REQUIRE(contactsdb.isInitialized());

    ContactsRingtonesTableRow testRow1(DB_ID_NONE, DB_ID_NONE, "/test/assets/path/ringtone.wr");

M module-db/tests/ContactsTable_tests.cpp => module-db/tests/ContactsTable_tests.cpp +6 -3
@@ 2,19 2,22 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <catch2/catch.hpp>
#include <filesystem>

#include "Databases/ContactsDB.hpp"
#include "Tables/ContactsTable.hpp"

#include "vfs.hpp"
#include <vfs.hpp>
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Contacts Table tests")
{
    Database::initialize();

    vfs.remove(ContactsDB::GetDBName());
    const auto contactsPath = (purefs::dir::getUserDiskPath() / "contacts.db").c_str();
    std::filesystem::remove(contactsPath);

    ContactsDB contactsdb;
    ContactsDB contactsdb{contactsPath};
    REQUIRE(contactsdb.isInitialized());

    ContactsTableRow testRow1 = {{.ID = DB_ID_NONE},

M module-db/tests/EventsRecord_tests.cpp => module-db/tests/EventsRecord_tests.cpp +4 -2
@@ 16,6 16,7 @@
#include "module-db/queries/calendar/QueryEventsSelectFirstUpcoming.hpp"

#include <vfs.hpp>
#include <purefs/filesystem_paths.hpp>

#include <stdint.h>
#include <stdio.h>


@@ 27,9 28,10 @@ TEST_CASE("Events Record tests")
{
    Database::initialize();

    vfs.remove(EventsDB::GetDBName());
    const auto eventsPath = (purefs::dir::getUserDiskPath() / "events.db").c_str();
    std::filesystem::remove(eventsPath);

    EventsDB eventsDb;
    EventsDB eventsDb{eventsPath};

    REQUIRE(eventsDb.isInitialized());


M module-db/tests/EventsTable_tests.cpp => module-db/tests/EventsTable_tests.cpp +4 -2
@@ 13,14 13,16 @@
#include <string>
#include <algorithm>
#include <iostream>
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Events Table tests")
{
    Database::initialize();

    vfs.remove(EventsDB::GetDBName());
    const auto eventsPath = (purefs::dir::getUserDiskPath() / "events.db").c_str();
    std::filesystem::remove(eventsPath);

    EventsDB eventsDb;
    EventsDB eventsDb{eventsPath};
    REQUIRE(eventsDb.isInitialized());

    auto &eventsTbl = eventsDb.events;

M module-db/tests/NotesRecord_tests.cpp => module-db/tests/NotesRecord_tests.cpp +2 -1
@@ 8,6 8,7 @@
#include <queries/notes/QueryNotesGetByText.hpp>
#include <queries/notes/QueryNoteRemove.hpp>
#include <queries/notes/QueryNoteStore.hpp>
#include <purefs/filesystem_paths.hpp>

#include "Database/Database.hpp"
#include "Databases/NotesDB.hpp"


@@ 16,7 17,7 @@ TEST_CASE("Notes Record tests")
{
    Database::initialize();

    auto notesDb = std::make_unique<NotesDB>();
    auto notesDb = std::make_unique<NotesDB>((purefs::dir::getUserDiskPath() / "notes.db").c_str());
    REQUIRE(notesDb->isInitialized());

    NotesRecordInterface notesRecordInterface{notesDb.get()};

M module-db/tests/NotesTable_tests.cpp => module-db/tests/NotesTable_tests.cpp +2 -1
@@ 6,12 6,13 @@
#include <Tables/NotesTable.hpp>
#include "Database/Database.hpp"
#include "Databases/NotesDB.hpp"
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Notes Table tests")
{
    Database::initialize();

    auto notesDb = std::make_unique<NotesDB>();
    auto notesDb = std::make_unique<NotesDB>((purefs::dir::getUserDiskPath() / "notes.db").c_str());
    REQUIRE(notesDb->isInitialized());

    NotesTable table{notesDb.get()};

M module-db/tests/NotificationsRecord_tests.cpp => module-db/tests/NotificationsRecord_tests.cpp +5 -2
@@ 12,20 12,23 @@
#include "module-db/queries/notifications/QueryNotificationsGetAll.hpp"

#include <vfs.hpp>
#include <filesystem>

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Notifications Record tests")
{
    Database::initialize();

    vfs.remove(NotificationsDB::GetDBName());
    const auto notificationsPath = (purefs::dir::getUserDiskPath() / "notifications.db").c_str();
    std::filesystem::remove(notificationsPath);

    NotificationsDB notificationsDb;
    NotificationsDB notificationsDb{notificationsPath};

    REQUIRE(notificationsDb.isInitialized());


M module-db/tests/NotificationsTable_tests.cpp => module-db/tests/NotificationsTable_tests.cpp +5 -2
@@ 13,14 13,17 @@
#include <string>
#include <algorithm>
#include <iostream>
#include <filesystem>
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Notifications Table tests")
{
    Database::initialize();

    vfs.remove(NotificationsDB::GetDBName());
    const auto notificationsPath = (purefs::dir::getUserDiskPath() / "notifications.db").c_str();
    std::filesystem::remove(notificationsPath);

    NotificationsDB notificationsDb;
    NotificationsDB notificationsDb{notificationsPath};
    REQUIRE(notificationsDb.isInitialized());

    auto &notificationsTbl = notificationsDb.notifications;

M module-db/tests/QueryInterface.cpp => module-db/tests/QueryInterface.cpp +4 -2
@@ 17,6 17,7 @@
#include <memory>
#include <module-db/queries/messages/sms/QuerySMSGetCount.hpp>
#include <module-utils/json/json11.hpp>
#include <purefs/filesystem_paths.hpp>

namespace db
{


@@ 37,8 38,9 @@ namespace db
TEST_CASE("Query interface")
{
    Database::initialize();
    auto contactsDB      = std::make_unique<ContactsDB>();
    auto smsDB           = std::make_unique<SmsDB>();

    auto contactsDB      = std::make_unique<ContactsDB>((purefs::dir::getUserDiskPath() / "contacts.db").c_str());
    auto smsDB           = std::make_unique<SmsDB>((purefs::dir::getUserDiskPath() / "sms.db").c_str());
    auto smsInterface    = std::make_unique<SMSRecordInterface>(smsDB.get(), contactsDB.get());
    auto threadInterface = std::make_unique<ThreadRecordInterface>(smsDB.get(), contactsDB.get());


M module-db/tests/SMSRecord_tests.cpp => module-db/tests/SMSRecord_tests.cpp +8 -5
@@ 15,11 15,12 @@
#include <vfs.hpp>

#include <algorithm>

#include <filesystem>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <module-db/queries/messages/sms/QuerySMSGetForList.hpp>
#include <purefs/filesystem_paths.hpp>

struct test
{


@@ 31,11 32,13 @@ TEST_CASE("SMS Record tests")
{
    Database::initialize();

    vfs.remove(ContactsDB::GetDBName());
    vfs.remove(SmsDB::GetDBName());
    const auto contactsPath = (purefs::dir::getUserDiskPath() / "contacts.db").c_str();
    const auto smsPath      = (purefs::dir::getUserDiskPath() / "sms.db").c_str();
    std::filesystem::remove(contactsPath);
    std::filesystem::remove(smsPath);

    auto smsDB      = std::make_unique<SmsDB>();
    auto contactsDB = std::make_unique<ContactsDB>();
    auto contactsDB = std::make_unique<ContactsDB>(contactsPath);
    auto smsDB      = std::make_unique<SmsDB>(smsPath);

    const uint32_t dateTest      = 123456789;
    const uint32_t dateSentTest  = 987654321;

M module-db/tests/SMSTable_tests.cpp => module-db/tests/SMSTable_tests.cpp +6 -3
@@ 1,7 1,7 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "vfs.hpp"
#include <vfs.hpp>

#include <catch2/catch.hpp>



@@ 9,15 9,18 @@
#include "Databases/SmsDB.hpp"

#include <algorithm>
#include <filesystem>
#include <purefs/filesystem_paths.hpp>
#include <cstring>

TEST_CASE("SMS Table tests")
{
    Database::initialize();

    vfs.remove(SmsDB::GetDBName());
    const auto smsPath = (purefs::dir::getUserDiskPath() / "sms.db").c_str();
    std::filesystem::remove(smsPath);

    SmsDB smsdb;
    SmsDB smsdb(smsPath);
    REQUIRE(smsdb.isInitialized());

    SMSTableRow testRow1 = {{.ID = 0},

M module-db/tests/SMSTemplateRecord_tests.cpp => module-db/tests/SMSTemplateRecord_tests.cpp +6 -3
@@ 7,9 7,11 @@
#include "Database/Database.hpp"
#include "Databases/SmsDB.hpp"

#include "vfs.hpp"
#include <vfs.hpp>
#include <purefs/filesystem_paths.hpp>

#include <algorithm>
#include <filesystem>

#include <cstdint>
#include <cstdio>


@@ 19,9 21,10 @@ TEST_CASE("SMS templates Record tests")
{
    Database::initialize();

    vfs.remove(SmsDB::GetDBName());
    const auto smsPath = (purefs::dir::getUserDiskPath() / "sms.db").c_str();
    std::filesystem::remove(smsPath);

    auto smsDB = std::make_unique<SmsDB>();
    auto smsDB = std::make_unique<SmsDB>(smsPath);
    REQUIRE(smsDB->isInitialized());

    SMSTemplateRecordInterface SMSTemplateRecordInterface(smsDB.get());

M module-db/tests/SMSTemplateTable_tests.cpp => module-db/tests/SMSTemplateTable_tests.cpp +5 -2
@@ 9,6 9,8 @@
#include "Tables/SMSTemplateTable.hpp"

#include <vfs.hpp>
#include <filesystem>
#include <purefs/filesystem_paths.hpp>

#include <algorithm>
#include <string>


@@ 19,9 21,10 @@ TEST_CASE("SMS Templates Table tests")
{
    Database::initialize();

    vfs.remove(SmsDB::GetDBName());
    const auto smsPath = (purefs::dir::getUserDiskPath() / "sms.db").c_str();
    std::filesystem::remove(smsPath);

    SmsDB smsDb;
    SmsDB smsDb{smsPath};
    REQUIRE(smsDb.isInitialized());

    auto &templatesTbl = smsDb.templates;

M module-db/tests/ThreadRecord_tests.cpp => module-db/tests/ThreadRecord_tests.cpp +8 -5
@@ 17,7 17,8 @@
#include "queries/messages/threads/QueryThreadRemove.hpp"
#include "queries/messages/threads/QueryThreadsGet.hpp"
#include "queries/messages/sms/QuerySMSGetLastByThreadID.hpp"
#include "vfs.hpp"
#include <vfs.hpp>
#include <purefs/filesystem_paths.hpp>

#include <algorithm>



@@ 29,12 30,14 @@ TEST_CASE("Thread Record tests")
{
    Database::initialize();

    vfs.remove(ContactsDB::GetDBName());
    vfs.remove(SmsDB::GetDBName());
    const auto contactsPath = (purefs::dir::getUserDiskPath() / "contacts.db").c_str();
    const auto smsPath      = (purefs::dir::getUserDiskPath() / "sms.db").c_str();
    std::filesystem::remove(contactsPath);
    std::filesystem::remove(smsPath);

    auto smsDB = std::make_unique<SmsDB>();
    auto smsDB = std::make_unique<SmsDB>(smsPath);
    REQUIRE(smsDB->isInitialized());
    auto contactsDB = std::make_unique<ContactsDB>();
    auto contactsDB = std::make_unique<ContactsDB>(contactsPath);
    REQUIRE(contactsDB->isInitialized());

    const uint32_t dateTest      = 123456789;

M module-db/tests/ThreadsTable_tests.cpp => module-db/tests/ThreadsTable_tests.cpp +6 -3
@@ 1,7 1,7 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "vfs.hpp"
#include <vfs.hpp>

#include <catch2/catch.hpp>



@@ 10,18 10,21 @@
#include "Tables/ThreadsTable.hpp"

#include <algorithm>
#include <filesystem>

#include <cstdint>
#include <cstdio>
#include <cstring>
#include <purefs/filesystem_paths.hpp>

TEST_CASE("Threads Table tests")
{
    Database::initialize();

    vfs.remove(SmsDB::GetDBName());
    const auto smsPath = (purefs::dir::getUserDiskPath() / "sms.db").c_str();
    std::filesystem::remove(smsPath);

    SmsDB smsdb;
    SmsDB smsdb{smsPath};
    REQUIRE(smsdb.isInitialized());

    ThreadsTableRow testRow1 = {{.ID = 0},

M module-db/tests/unittest.cpp => module-db/tests/unittest.cpp +34 -32
@@ 1,7 1,7 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "vfs.hpp"
#include <vfs.hpp>

#include <catch2/catch.hpp>



@@ 11,6 11,7 @@
#include "Tables/SMSTable.hpp"

#include <algorithm>
#include <fstream>
#include <iostream>

#include <cstdint>


@@ 94,10 95,11 @@ TEST_CASE("Create and destroy simple database")
    SECTION("Store database into backup file")
    {
        std::string backupPathDB = USER_PATH("testbackup.db");
        vfs.remove(backupPathDB.c_str());
        std::remove(backupPathDB.c_str());
        Database testDB("test.db");
        REQUIRE(testDB.storeIntoFile(backupPathDB) == true);
        REQUIRE(vfs.fileExists(backupPathDB.c_str()) == true);
        std::ifstream f(backupPathDB);
        REQUIRE(f.good() == true);
    }

    Database::deinitialize();


@@ 108,21 110,21 @@ class ScopedDir
  public:
    ScopedDir(std::string p) : path(p)
    {
        vfs.mkdir(path.c_str());
        REQUIRE(std::filesystem::create_directory(path.c_str()));
    }

    ~ScopedDir()
    {
        vfs.deltree(path.c_str());
        REQUIRE(std::filesystem::remove(path.c_str()));
    }

    auto operator()(std::string file = "") -> fs::path
    auto operator()(std::string file = "") -> std::filesystem::path
    {
        return path / file;
    }

  private:
    fs::path path;
    std::filesystem::path path;
};

TEST_CASE("Database initialization scripts")


@@ 154,20 156,20 @@ TEST_CASE("Database initialization scripts")
    {
        ScopedDir dir(USER_PATH("scripts"));

        auto file = vfs.fopen(dir("test_1.sql").c_str(), "w");
        vfs.fclose(file);
        auto file = std::fopen(dir("test_1.sql").c_str(), "w");
        std::fclose(file);

        file = vfs.fopen(dir("test_021.sql").c_str(), "w");
        vfs.fclose(file);
        file = std::fopen(dir("test_021.sql").c_str(), "w");
        std::fclose(file);

        file = vfs.fopen(dir("test_011.sql").c_str(), "w");
        vfs.fclose(file);
        file = std::fopen(dir("test_011.sql").c_str(), "w");
        std::fclose(file);

        file = vfs.fopen(dir("test_003.sql").c_str(), "w");
        vfs.fclose(file);
        file = std::fopen(dir("test_003.sql").c_str(), "w");
        std::fclose(file);

        file = vfs.fopen(dir("noprefix_003.sql").c_str(), "w");
        vfs.fclose(file);
        file = std::fopen(dir("noprefix_003.sql").c_str(), "w");
        std::fclose(file);

        Database db(dir("test.db").c_str());
        DatabaseInitializer initializer(&db);


@@ 184,12 186,12 @@ TEST_CASE("Database initialization scripts")
    {
        ScopedDir dir(USER_PATH("scripts"));

        auto file = vfs.fopen(dir("test_1.sql").c_str(), "w");
        auto file = std::fopen(dir("test_1.sql").c_str(), "w");

        vfs.fprintf(file, "%s\n", script_create);
        vfs.fprintf(file, "%s\n", script_insert);
        std::fprintf(file, "%s\n", script_create);
        std::fprintf(file, "%s\n", script_insert);

        vfs.fclose(file);
        std::fclose(file);

        Database db(dir("test.db").c_str());
        DatabaseInitializer initializer(&db);


@@ 202,8 204,8 @@ TEST_CASE("Database initialization scripts")
    {
        ScopedDir dir(USER_PATH("scripts"));

        auto file = vfs.fopen(dir("test_1.sql").c_str(), "w");
        vfs.fclose(file);
        auto file = std::fopen(dir("test_1.sql").c_str(), "w");
        std::fclose(file);

        Database db(dir("test.db").c_str());
        DatabaseInitializer initializer(&db);


@@ 216,9 218,9 @@ TEST_CASE("Database initialization scripts")
    {
        ScopedDir dir(USER_PATH("scripts"));

        auto file = vfs.fopen(dir("test_1.sql").c_str(), "w");
        vfs.fprintf(file, "%s\n", script_comment);
        vfs.fclose(file);
        auto file = std::fopen(dir("test_1.sql").c_str(), "w");
        std::fprintf(file, "%s\n", script_comment);
        std::fclose(file);

        Database db(dir("test.db").c_str());
        DatabaseInitializer initializer(&db);


@@ 231,9 233,9 @@ TEST_CASE("Database initialization scripts")
    {
        ScopedDir dir(USER_PATH("scripts"));

        auto file = vfs.fopen(dir("test_1.sql").c_str(), "w");
        vfs.fprintf(file, "%s\n", script_create);
        vfs.fclose(file);
        auto file = std::fopen(dir("test_1.sql").c_str(), "w");
        std::fprintf(file, "%s\n", script_create);
        std::fclose(file);

        Database db(dir("test.db").c_str());
        DatabaseInitializer initializer(&db);


@@ 246,9 248,9 @@ TEST_CASE("Database initialization scripts")
    {
        ScopedDir dir(USER_PATH("scripts"));

        auto file = vfs.fopen(dir("test_1.sql").c_str(), "w");
        vfs.fprintf(file, "%s\n", script_invalid);
        vfs.fclose(file);
        auto file = std::fopen(dir("test_1.sql").c_str(), "w");
        std::fprintf(file, "%s\n", script_invalid);
        std::fclose(file);

        Database db(dir("test.db").c_str());
        DatabaseInitializer initializer(&db);

M module-services/service-db/ServiceDB.cpp => module-services/service-db/ServiceDB.cpp +9 -8
@@ 34,6 34,7 @@
#include <MessageType.hpp>
#include <NotesRecord.hpp>
#include <NotificationsRecord.hpp>
#include <purefs/filesystem_paths.hpp>
#include <SMSRecord.hpp>
#include <SMSTemplateRecord.hpp>
#include <Service/Bus.hpp>


@@ 534,14 535,14 @@ sys::ReturnCodes ServiceDB::InitHandler()
    Database::initialize();

    // Create databases
    contactsDB      = std::make_unique<ContactsDB>();
    smsDB           = std::make_unique<SmsDB>();
    alarmsDB        = std::make_unique<AlarmsDB>();
    notesDB         = std::make_unique<NotesDB>();
    calllogDB       = std::make_unique<CalllogDB>();
    countryCodesDB  = std::make_unique<CountryCodesDB>();
    notificationsDB = std::make_unique<NotificationsDB>();
    eventsDB        = std::make_unique<EventsDB>();
    contactsDB      = std::make_unique<ContactsDB>((purefs::dir::getUserDiskPath() / "contacts.db").c_str());
    smsDB           = std::make_unique<SmsDB>((purefs::dir::getUserDiskPath() / "sms.db").c_str());
    alarmsDB        = std::make_unique<AlarmsDB>((purefs::dir::getUserDiskPath() / "alarms.db").c_str());
    notesDB         = std::make_unique<NotesDB>((purefs::dir::getUserDiskPath() / "notes.db").c_str());
    calllogDB       = std::make_unique<CalllogDB>((purefs::dir::getUserDiskPath() / "callog.db").c_str());
    countryCodesDB  = std::make_unique<CountryCodesDB>("country-codes.db");
    notificationsDB = std::make_unique<NotificationsDB>((purefs::dir::getUserDiskPath() / "notifications.db").c_str());
    eventsDB        = std::make_unique<EventsDB>((purefs::dir::getUserDiskPath() / "events.db").c_str());

    // Create record interfaces
    contactRecordInterface       = std::make_unique<ContactRecordInterface>(contactsDB.get());

M module-utils/Utils.hpp => module-utils/Utils.hpp +11 -0
@@ 240,4 240,15 @@ namespace utils
#endif
    }

    namespace filesystem
    {
        static inline long int filelength(std::FILE *file) noexcept
        {
            if (file == nullptr) {
                return 0;
            }
            std::fseek(file, 0, SEEK_END);
            return std::ftell(file);
        }
    } // namespace filesystem
} // namespace utils

M module-utils/i18n/i18n.hpp => module-utils/i18n/i18n.hpp +2 -6
@@ 1,12 1,10 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef UNTITLED_I18_HPP
#define UNTITLED_I18_HPP

#pragma once
#include "json/json11.hpp"
#include <string>
#include "vfs.hpp"
#include <vfs.hpp>
#include "log/log.hpp"

#include "thread.hpp"


@@ 62,5 60,3 @@ namespace utils
        return utils::localize.get(text);
    };
} // namespace utils

#endif // UNTITLED_I18_HPP

M module-utils/test/unittest_utils.cpp => module-utils/test/unittest_utils.cpp +43 -0
@@ 12,6 12,16 @@

#include "Utils.hpp"

class vfs vfs;

struct vfs_initializer
{
    vfs_initializer()
    {
        vfs.Init();
    }
} vfs_initializer;

TEST_CASE("Split tests")
{
    std::string delimiter = "\r\n";


@@ 269,3 279,36 @@ TEST_CASE("Fill leading digit in string")
    REQUIRE(utils::addLeadingZeros(test, 3) == "045");
    REQUIRE(utils::addLeadingZeros(test, 4) == "0045");
}

class ScopedDir
{
  public:
    ScopedDir(const std::filesystem::path &dirPath) : dirPath{dirPath}
    {
        REQUIRE(std::filesystem::create_directory(dirPath));
    }

    ~ScopedDir()
    {
        REQUIRE(std::filesystem::remove(dirPath));
    }

    auto operator()(std::string file = "") -> std::filesystem::path
    {
        return dirPath.c_str() + file;
    }

  private:
    std::filesystem::path dirPath;
};

TEST_CASE("Read file length")
{
    ScopedDir dir(USER_PATH("test"));
    auto *file = std::fopen(dir("test.txt").c_str(), "w");
    REQUIRE(file != nullptr);
    std::array<int, 3> v = {42, -1, 7};
    std::fwrite(v.data(), sizeof(v[0]), v.size(), file);
    REQUIRE(utils::filesystem::filelength(file) == static_cast<long>(sizeof(v[0]) * v.size()));
    REQUIRE(std::fclose(file) == 0);
}