proper cmake

This commit is contained in:
2023-06-04 16:10:06 +02:00
parent 13a8b4c35d
commit fdcb0cf0c4
154 changed files with 1273 additions and 1620 deletions

View File

@@ -1,39 +0,0 @@
//
// Created by Stepan Usatiuk on 27.04.2023.
//
#include "BuzhashTest.h"
#include "../src/chunkers/Buzhash.h"
std::unique_ptr<TestGroup> BuzhashTest::operator()() {
auto tg = std::make_unique<TestGroup>("Buzhash tests");
tg->addTest(std::make_unique<Test>("Simple buzhash test", std::function<bool()>([]() {
std::string loremipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
for (int i = 15; i < 49; i++) {
Buzhash b(i);
std::string p1 = "reprehenderit in voluptate velit esse cillum dolore";
for (auto c: p1) b.feed(static_cast<uint8_t>(c));
auto h1 = b.get();
Buzhash b2(i);
bool h1found = false;
for (int i = 0; i < loremipsum.length(); i++) {
b2.feed((uint8_t) loremipsum[i]);
if (b2.get() == h1) {
HelpfulAssert<int>()(i, loremipsum.find("e eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non p"));
h1found = true;
break;
}
}
HelpfulAssert<bool>()(h1found, true);
}
return true;
})));
return tg;
}

View File

@@ -1,16 +0,0 @@
//
// Created by Stepan Usatiuk on 27.04.2023.
//
#ifndef SEMBACKUP_BUZHASHTEST_H
#define SEMBACKUP_BUZHASHTEST_H
#include "utils/TestGroupGenerator.h"
class BuzhashTest : public TestGroupGenerator {
public:
std::unique_ptr<TestGroup> operator()() override;
};
#endif//SEMBACKUP_BUZHASHTEST_H

View File

@@ -1,30 +0,0 @@
//
// Created by Stepan Usatiuk on 10.05.2023.
//
#include "CLITestWrapper.h"
#include "utils/Cleaner.h"
std::unique_ptr<TestGroup> CLITestWrapper::operator()() {
auto tg = std::make_unique<TestGroup>("CLI tests");
tg->addTest(std::make_unique<Test>("Test backup", std::function<bool()>([]() {
int ret = system("../tests/clitests/backup.sh");
HelpfulAssert<int>()(WEXITSTATUS(ret), 0);
return true;
})));
tg->addTest(std::make_unique<Test>("Test ignore", std::function<bool()>([]() {
int ret = system("../tests/clitests/ignore.sh");
HelpfulAssert<int>()(WEXITSTATUS(ret), 0);
return true;
})));
tg->addTest(std::make_unique<Test>("Test diff", std::function<bool()>([]() {
int ret = system("../tests/clitests/diff.sh");
HelpfulAssert<int>()(WEXITSTATUS(ret), 0);
return true;
})));
return tg;
}

View File

@@ -1,15 +0,0 @@
//
// Created by Stepan Usatiuk on 10.05.2023.
//
#ifndef SEMBACKUP_CLITESTWRAPPER_H
#define SEMBACKUP_CLITESTWRAPPER_H
#include "utils/TestGroupGenerator.h"
class CLITestWrapper : public TestGroupGenerator {
public:
std::unique_ptr<TestGroup> operator()() override;
};
#endif//SEMBACKUP_CLITESTWRAPPER_H

28
tests/CMakeLists.txt Normal file
View File

@@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 3.22)
# GoogleTest requires at least C++14
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
cmake_policy(SET CMP0135 NEW)
endif ()
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.12.1
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
include(GoogleTest)
add_subdirectory(utils)
add_subdirectory(chunkers)
add_subdirectory(clitests)
add_subdirectory(crypto)
add_subdirectory(fulltests)
add_subdirectory(repo)

View File

@@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.22)
add_executable(
BuzhashTest
srcs/BuzhashTest.cpp
)
target_link_libraries(
BuzhashTest PRIVATE
GTest::gtest_main chunkers
)
gtest_discover_tests(BuzhashTest)

View File

@@ -0,0 +1,31 @@
//
// Created by Stepan Usatiuk on 27.04.2023.
//
#include "Buzhash.h"
#include <gtest/gtest.h>
// Demonstrate some basic assertions.
TEST(BuzhashTest, SimpleTest) {
std::string loremipsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
for (int i = 15; i < 49; i++) {
Buzhash b(i);
std::string p1 = "reprehenderit in voluptate velit esse cillum dolore";
for (auto c: p1) b.feed(static_cast<uint8_t>(c));
auto h1 = b.get();
Buzhash b2(i);
bool h1found = false;
for (int i = 0; i < loremipsum.length(); i++) {
b2.feed((uint8_t) loremipsum[i]);
if (b2.get() == h1) {
EXPECT_EQ(i, loremipsum.find("e eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non p"));
h1found = true;
break;
}
}
EXPECT_EQ(h1found, true);
}
}

View File

@@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.22)
add_executable(
CLITests
srcs/CLITestWrapper.cpp
)
add_dependencies(CLITests backup)
target_link_libraries(
CLITests PRIVATE
GTest::gtest_main testUtils
)
gtest_discover_tests(CLITests)

View File

@@ -2,7 +2,8 @@
TESTSIZE=16
CMD=./sembackup
# TODO: Don't hardcode this
CMD="../../src/backup"
rm -rf testdata
rm -rf testdir

View File

@@ -1,6 +1,7 @@
#!/bin/bash
CMD=./sembackup
# TODO: Don't hardcode this
CMD="../../src/backup"
rm -rf testdata
rm -rf testdir

View File

@@ -1,6 +1,7 @@
#!/bin/bash
CMD=./sembackup
# TODO: Don't hardcode this
CMD="../../src/backup"
rm -rf testdata
rm -rf testdir

View File

@@ -0,0 +1,23 @@
//
// Created by Stepan Usatiuk on 10.05.2023.
//
#include "Cleaner.h"
#include <gtest/gtest.h>
//TODO: Don't hardcode scripts
TEST(CLITest, Backup) {
int ret = system("../../../tests/clitests/scripts/backup.sh");
EXPECT_EQ(WEXITSTATUS(ret), 0);
}
TEST(CLITest, Ignore) {
int ret = system("../../../tests/clitests/scripts/ignore.sh");
EXPECT_EQ(WEXITSTATUS(ret), 0);
}
TEST(CLITest, Diff) {
int ret = system("../../../tests/clitests/scripts/diff.sh");
EXPECT_EQ(WEXITSTATUS(ret), 0);
}

View File

@@ -1,40 +0,0 @@
//
// Created by Stepan Usatiuk on 30.04.2023.
//
#include "AESTest.h"
#include "../../src/crypto/AES.h"
std::unique_ptr<TestGroup> AESTest::operator()() {
auto tg = std::make_unique<TestGroup>("AES tests");
tg->addTest(std::make_unique<Test>("Simple AESTest test", std::function<bool()>([]() {
std::string in = "hello1";
auto enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
auto dec = AES::decrypt(enc, "p1", "e");
HelpfulAssert<std::string>()(in, std::string(dec.begin(), dec.end()));
in = "1234567890asdfg";
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
dec = AES::decrypt(enc, "p1", "e");
HelpfulAssert<std::string>()(in, std::string(dec.begin(), dec.end()));
in = "1234567890asdfgh";
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
dec = AES::decrypt(enc, "p1", "e");
HelpfulAssert<std::string>()(in, std::string(dec.begin(), dec.end()));
in = "1234567890asdfghe";
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
dec = AES::decrypt(enc, "p1", "e");
HelpfulAssert<std::string>()(in, std::string(dec.begin(), dec.end()));
in = "1234567890asdfgheq";
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
dec = AES::decrypt(enc, "p1", "e");
HelpfulAssert<std::string>()(in, std::string(dec.begin(), dec.end()));
return true;
})));
return tg;
}

View File

@@ -1,16 +0,0 @@
//
// Created by Stepan Usatiuk on 30.04.2023.
//
#ifndef SEMBACKUP_AESTEST_H
#define SEMBACKUP_AESTEST_H
#include "../utils/TestGroupGenerator.h"
class AESTest : public TestGroupGenerator {
public:
std::unique_ptr<TestGroup> operator()() override;
};
#endif//SEMBACKUP_AESTEST_H

View File

@@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.22)
add_executable(
CryptoTests
srcs/CryptoTests.cpp
)
target_link_libraries(
CryptoTests PRIVATE
GTest::gtest_main crypto
)
gtest_discover_tests(CryptoTests)

View File

@@ -1,25 +0,0 @@
//
// Created by Stepan Usatiuk on 15.04.2023.
//
#include "MD5Test.h"
std::unique_ptr<TestGroup> MD5Test::operator()() {
auto tg = std::make_unique<TestGroup>("MD5 tests");
tg->addTest(std::make_unique<Test>("Simple MD5 test", std::function<bool()>([]() {
std::vector<char> data{'h', 'e', 'l', 'l', 'o'};
std::array<unsigned char, 16> excepted{0x5d, 0x41, 0x40, 0x2a, 0xbc, 0x4b, 0x2a, 0x76, 0xb9, 0x71, 0x9d, 0x91, 0x10, 0x17, 0xc5, 0x92};
auto out = MD5::calculate(data);
HelpfulAssert<size_t>()(out.size(), 16);
for (int i = 0; i < out.size(); i++) {
HelpfulAssert<unsigned char>()(out[i], excepted[i]);
}
return true;
})));
return tg;
}

View File

@@ -1,17 +0,0 @@
//
// Created by Stepan Usatiuk on 15.04.2023.
//
#ifndef SEMBACKUP_MD5TEST_H
#define SEMBACKUP_MD5TEST_H
#include "../../src/crypto/MD5.h"
#include "../utils/TestGroupGenerator.h"
class MD5Test : public TestGroupGenerator {
public:
std::unique_ptr<TestGroup> operator()() override;
};
#endif//SEMBACKUP_MD5TEST_H

View File

@@ -0,0 +1,47 @@
//
// Created by Stepan Usatiuk on 30.04.2023.
//
#include "AES.h"
#include "MD5.h"
#include <gtest/gtest.h>
TEST(CryptoTests, AES) {
std::string in = "hello1";
auto enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
auto dec = AES::decrypt(enc, "p1", "e");
EXPECT_EQ(in, std::string(dec.begin(), dec.end()));
in = "1234567890asdfg";
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
dec = AES::decrypt(enc, "p1", "e");
EXPECT_EQ(in, std::string(dec.begin(), dec.end()));
in = "1234567890asdfgh";
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
dec = AES::decrypt(enc, "p1", "e");
EXPECT_EQ(in, std::string(dec.begin(), dec.end()));
in = "1234567890asdfghe";
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
dec = AES::decrypt(enc, "p1", "e");
EXPECT_EQ(in, std::string(dec.begin(), dec.end()));
in = "1234567890asdfgheq";
enc = AES::encrypt(std::vector<char>(in.begin(), in.end()), "p1", "e");
dec = AES::decrypt(enc, "p1", "e");
EXPECT_EQ(in, std::string(dec.begin(), dec.end()));
}
TEST(CryptoTests, MD5) {
std::vector<char> data{'h', 'e', 'l', 'l', 'o'};
std::array<unsigned char, 16> excepted{0x5d, 0x41, 0x40, 0x2a, 0xbc, 0x4b, 0x2a, 0x76, 0xb9, 0x71, 0x9d, 0x91, 0x10, 0x17, 0xc5, 0x92};
auto out = MD5::calculate(data);
EXPECT_EQ(out.size(), 16);
for (int i = 0; i < out.size(); i++) {
EXPECT_EQ(static_cast<uint8_t>(out[i]), excepted[i]);
}
}

View File

@@ -0,0 +1,14 @@
cmake_minimum_required(VERSION 3.22)
add_executable(
FullTest
srcs/FullTest.cpp
)
target_link_libraries(
FullTest PRIVATE
GTest::gtest_main commands utils testUtils repo
)
gtest_discover_tests(FullTest)

View File

@@ -1,418 +0,0 @@
//
// Created by Stepan Usatiuk on 16.04.2023.
//
#include "FullTest.h"
#include "../../src/Logger.h"
#include "../../src/commands/CommandRestore.h"
#include "../../src/commands/CommandRun.h"
#include "../../src/repo/FileRepository.h"
#include "../utils/Cleaner.h"
#include <filesystem>
#include <functional>
#include <string>
void randomChange(std::string path) {
std::fstream s(path);
auto pos = rand() % 50;
s.seekp(pos, std::ios::beg);
char out = rand() % 254;
s.write(&out, 1);
}
std::unique_ptr<TestGroup> FullTest::operator()() {
auto tg = std::make_unique<TestGroup>("Full tests");
tg->addTest(std::make_unique<Test>("Simple backup/restore test", std::function<bool()>([]() {
Cleaner c({"testfrom", "testto", "testtores"});
int aid = -1;
{
std::filesystem::create_directories("testfrom");
for (int i = 0; i < 257; i++) {
std::ofstream o(std::filesystem::path("testfrom") / ("f" + std::to_string(i)), std::ios::binary | std::ios::out | std::ios::trunc);
for (int j = 0; j < i; j++) o.put(j % 256);
}
std::filesystem::create_directories("testfrom/testdir");
Config conf;
conf.add("repo", "testto").add("from", "testfrom");
auto repo = std::make_unique<FileRepository>(conf);
repo->init();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRun run;
run.run(Context{&logger, repo.get()});
aid = repo->getObjects(Object::ObjectType::Archive).begin()->second;
}
{
Config conf;
conf.add("repo", "testto").add("aid", std::to_string(aid)).add("to", "testtores");
auto repo = std::make_unique<FileRepository>(conf);
repo->open();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRestore cmd;
cmd.run(Context{&logger, repo.get()});
}
{
try {
HelpfulAssert<bool>()(std::filesystem::is_directory("testtores/testdir"), true);
} catch (...) {
std::cerr << "Empty directory doesn't exist!" << std::endl;
throw;
}
for (int i = 0; i < 257; i++) {
std::ifstream o(std::filesystem::path("testtores") / ("f" + std::to_string(i)), std::ios::binary | std::ios::in);
try {
HelpfulAssert<bool>()(o.is_open(), true);
for (int j = 0; j < i; j++) {
char c;
HelpfulAssert<bool>()(o.get(c).operator bool(), true);
HelpfulAssert<char>()(j % 256, c);
}
} catch (...) {
std::cerr << "Error comparing file " << i << std::endl;
throw;
}
}
}
return true;
})));
tg->addTest(std::make_unique<Test>("Simple backup/restore with ignore test", std::function<bool()>([]() {
Cleaner c({"testfrom", "testto", "testtores"});
int aid = -1;
{
std::filesystem::create_directories("testfrom");
for (int i = 0; i < 257; i++) {
std::ofstream o(std::filesystem::path("testfrom") / ("f" + std::to_string(i)), std::ios::binary | std::ios::out | std::ios::trunc);
for (int j = 0; j < i; j++) o.put(j % 256);
}
std::filesystem::create_directories("testfrom/testdir");
std::filesystem::create_directories("testfrom/testdir2/testdir3");
std::filesystem::create_directories("testfrom/testdir2/testdir4");
{
std::ofstream file("testfrom/testdir2/.ignore");
file << "hello.txt";
}
{
std::ofstream file("testfrom/testdir2/testdir3/.ignore");
file << ".*\\.txt";
}
{
std::ofstream file("testfrom/testdir2/hello.txt");
file << "hello";
}
{
std::ofstream file("testfrom/testdir2/testdir3/hello.txt");
file << "hello2";
}
{
std::ofstream file("testfrom/testdir2/testdir3/asdf.txt");
file << "asdf1";
}
{
std::ofstream file("testfrom/testdir2/testdir4/asdf.txt");
file << "asdf2";
}
Config conf;
conf.add("repo", "testto").add("from", "testfrom");
auto repo = std::make_unique<FileRepository>(conf);
repo->init();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRun cmd;
cmd.run(Context{&logger, repo.get()});
aid = repo->getObjects(Object::ObjectType::Archive).begin()->second;
}
{
Config conf;
conf.add("repo", "testto").add("aid", std::to_string(aid)).add("to", "testtores");
auto repo = std::make_unique<FileRepository>(conf);
repo->open();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRestore cmd;
cmd.run(Context{&logger, repo.get()});
}
{
HelpfulAssert<bool>()(std::filesystem::is_directory("testtores/testdir"), true);
for (int i = 0; i < 257; i++) {
std::ifstream o(std::filesystem::path("testtores") / ("f" + std::to_string(i)), std::ios::binary | std::ios::in);
HelpfulAssert<bool>()(o.is_open(), true);
for (int j = 0; j < i; j++) {
char c;
HelpfulAssert<bool>()(o.get(c).operator bool(), true);
HelpfulAssert<char>()(j % 256, c);
}
}
{
std::ifstream file("testtores/testdir2/.ignore");
std::string s;
file >> s;
HelpfulAssert<std::string>()(s, "hello.txt");
}
{
std::ifstream file("testtores/testdir2/testdir3/.ignore");
std::string s;
file >> s;
HelpfulAssert<std::string>()(s, ".*\\.txt");
}
{
std::ifstream file("testtores/testdir2/hello.txt");
HelpfulAssert<bool>()(!file, true);
}
{
std::ifstream file("testtores/testdir2/testdir3/hello.txt");
HelpfulAssert<bool>()(!file, true);
}
{
std::ifstream file("testtores/testdir2/testdir3/asdf.txt");
HelpfulAssert<bool>()(!file, true);
}
{
std::ifstream file("testtores/testdir2/testdir4/asdf.txt");
std::string s;
file >> s;
HelpfulAssert<std::string>()(s, "asdf2");
}
}
return true;
})));
tg->addTest(std::make_unique<Test>("Backup/restore test with compression", std::function<bool()>([]() {
Cleaner c({"testfrom", "testto", "testtores"});
int aid = -1;
{
std::filesystem::create_directories("testfrom");
for (int i = 0; i < 257; i++) {
std::ofstream o(std::filesystem::path("testfrom") / ("f" + std::to_string(i)), std::ios::binary | std::ios::out | std::ios::trunc);
for (int j = 0; j < i; j++) o.put(j % 256);
}
std::filesystem::create_directories("testfrom/testdir");
Config conf;
conf.add("repo", "testto").add("compression", "zlib").add("from", "testfrom");
auto repo = std::make_unique<FileRepository>(conf);
repo->init();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRun cmd;
cmd.run(Context{&logger, repo.get()});
aid = repo->getObjects(Object::ObjectType::Archive).begin()->second;
}
{
Config conf;
conf.add("repo", "testto").add("aid", std::to_string(aid)).add("to", "testtores");
auto repo = std::make_unique<FileRepository>(conf);
repo->open();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRestore cmd;
cmd.run(Context{&logger, repo.get()});
}
{
HelpfulAssert<bool>()(std::filesystem::is_directory("testtores/testdir"), true);
for (int i = 0; i < 257; i++) {
std::ifstream o(std::filesystem::path("testtores") / ("f" + std::to_string(i)), std::ios::binary | std::ios::in);
HelpfulAssert<bool>()(o.is_open(), true);
for (int j = 0; j < i; j++) {
char c;
HelpfulAssert<bool>()(o.get(c).operator bool(), true);
HelpfulAssert<char>()(j % 256, c);
}
}
}
return true;
})));
tg->addTest(std::make_unique<Test>("Backup/restore test with compression/encryption", std::function<bool()>([]() {
Cleaner c({"testfrom", "testto", "testtores"});
int aid = -1;
{
std::filesystem::create_directories("testfrom");
for (int i = 0; i < 257; i++) {
std::ofstream o(std::filesystem::path("testfrom") / ("f" + std::to_string(i)), std::ios::binary | std::ios::out | std::ios::trunc);
for (int j = 0; j < i; j++) o.put(j % 256);
}
std::filesystem::create_directories("testfrom/testdir");
Config conf;
conf.add("repo", "testto").add("compression", "zlib").add("from", "testfrom").add("encryption", "aes").add("password", "testp").add("salt", "tests");
auto repo = std::make_unique<FileRepository>(conf);
repo->init();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRun cmd;
cmd.run(Context{&logger, repo.get()});
aid = repo->getObjects(Object::ObjectType::Archive).begin()->second;
}
{
Config conf;
conf.add("repo", "testto");
auto repo = std::make_unique<FileRepository>(conf);
bool ok = true;
try {
HelpfulAssert<bool>()(repo->open(), false);
ok = false;
} catch (...) {}
HelpfulAssert<bool>()(ok, true);
}
{
Config conf;
conf.add("repo", "testto").add("password", "testp").add("aid", std::to_string(aid)).add("to", "testtores");
auto repo = std::make_unique<FileRepository>(conf);
repo->open();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRestore cmd;
cmd.run(Context{&logger, repo.get()});
}
{
HelpfulAssert<bool>()(std::filesystem::is_directory("testtores/testdir"), true);
for (int i = 0; i < 257; i++) {
std::ifstream o(std::filesystem::path("testtores") / ("f" + std::to_string(i)), std::ios::binary | std::ios::in);
HelpfulAssert<bool>()(o.is_open(), true);
for (int j = 0; j < i; j++) {
char c;
HelpfulAssert<bool>()(o.get(c).operator bool(), true);
HelpfulAssert<char>()(j % 256, c);
}
}
}
return true;
})));
tg->addTest(std::make_unique<Test>("Repo data fuzz test", std::function<bool()>([]() {
srand(time(nullptr));
std::vector<Config> confs;
Config conf;
conf.add("repo", "testto").add("compression", "none").add("from", "testfrom").add("encryption", "none").add("password", "testp").add("salt", "tests").add("progress", "none");
confs.emplace_back(conf);
conf = Config();
conf.add("repo", "testto").add("compression", "zlib").add("from", "testfrom").add("encryption", "none").add("password", "testp").add("salt", "tests").add("progress", "none");
confs.emplace_back(conf);
conf = Config();
conf.add("repo", "testto").add("compression", "none").add("from", "testfrom").add("encryption", "zlib").add("password", "testp").add("salt", "tests").add("progress", "none");
confs.emplace_back(conf);
conf = Config();
conf.add("repo", "testto").add("compression", "zlib").add("from", "testfrom").add("encryption", "aes").add("password", "testp").add("salt", "tests").add("progress", "none");
confs.emplace_back(conf);
for (auto const &conf: confs) {
for (uint8_t filetobreak = 1; filetobreak <= 15; filetobreak++) {
std::cout << static_cast<int>(filetobreak) << " / 15 tests done" << std::endl;
for (uint8_t cutoff = 1; cutoff < 20; cutoff++) {
Cleaner c({"testfrom", "testto", "testtores"});
int aid = -1;
{
std::filesystem::create_directories("testfrom");
for (int i = 0; i < 2; i++) {
std::ofstream o(std::filesystem::path("testfrom") / ("f" + std::to_string(i)), std::ios::binary | std::ios::out | std::ios::trunc);
for (int j = 0; j < i; j++) o.put(j % 2);
}
auto repo = std::make_unique<FileRepository>(conf);
repo->init();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRun cmd;
cmd.run(Context{&logger, repo.get()});
aid = repo->getObjects(Object::ObjectType::Archive).begin()->second;
}
{
if (filetobreak & 0b00000001) {
for (int i = 0; i < cutoff; i++)
randomChange("testto/1");
if (cutoff > 5)
std::filesystem::resize_file("testto/1", std::filesystem::file_size("testto/1") - cutoff);
}
if (filetobreak & 0b00000010) {
for (int i = 0; i < cutoff; i++)
randomChange("testto/index");
if (cutoff > 5)
std::filesystem::resize_file("testto/index", std::filesystem::file_size("testto/index") - cutoff);
}
if (filetobreak & 0b00000100) {
for (int i = 0; i < cutoff; i++)
randomChange("testto/offsets");
if (cutoff > 5)
std::filesystem::resize_file("testto/offsets", std::filesystem::file_size("testto/offsets") - cutoff);
}
if (filetobreak & 0b00001000) {
for (int i = 0; i < cutoff; i++)
randomChange("testto/info");
if (cutoff > 5)
std::filesystem::resize_file("testto/info", std::filesystem::file_size("testto/info") - cutoff);
}
}
{
bool ok = true;
try {
Config confr = conf;
confr.add("aid", std::to_string(aid)).add("to", "testtores");
auto repo = std::make_unique<FileRepository>(confr);
repo->open();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRestore cmd;
cmd.run(Context{&logger, repo.get()});
auto outstr = runnerout.str();
if (outstr.find("Error") == std::string::npos)
ok = false;
} catch (...) {}
HelpfulAssert<bool>()(ok, true);
}
}
}
}
return true;
})));
return tg;
}

View File

@@ -1,17 +0,0 @@
//
// Created by Stepan Usatiuk on 16.04.2023.
//
#ifndef SEMBACKUP_FULLTEST_H
#define SEMBACKUP_FULLTEST_H
#include "../utils/TestGroupGenerator.h"
class FullTest : public TestGroupGenerator {
public:
std::unique_ptr<TestGroup> operator()() override;
};
#endif//SEMBACKUP_FULLTEST_H

View File

@@ -0,0 +1,402 @@
//
// Created by Stepan Usatiuk on 16.04.2023.
//
#include <gtest/gtest.h>
#include "Cleaner.h"
#include "CommandRestore.h"
#include "CommandRun.h"
#include "FileRepository.h"
#include "Logger.h"
#include <filesystem>
#include <functional>
#include <string>
void randomChange(std::string path) {
std::fstream s(path);
auto pos = rand() % 50;
s.seekp(pos, std::ios::beg);
char out = rand() % 254;
s.write(&out, 1);
}
TEST(FullTest, Simple) {
Cleaner c({"testfrom", "testto", "testtores"});
int aid = -1;
{
std::filesystem::create_directories("testfrom");
for (int i = 0; i < 257; i++) {
std::ofstream o(std::filesystem::path("testfrom") / ("f" + std::to_string(i)), std::ios::binary | std::ios::out | std::ios::trunc);
for (int j = 0; j < i; j++) o.put(static_cast<char>(j % 256));
}
std::filesystem::create_directories("testfrom/testdir");
Config conf;
conf.add("repo", "testto").add("from", "testfrom");
auto repo = std::make_unique<FileRepository>(conf);
repo->init();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRun run;
run.run(Context{&logger, repo.get()});
aid = repo->getObjects(Object::ObjectType::Archive).begin()->second;
}
{
Config conf;
conf.add("repo", "testto").add("aid", std::to_string(aid)).add("to", "testtores");
auto repo = std::make_unique<FileRepository>(conf);
repo->open();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRestore cmd;
cmd.run(Context{&logger, repo.get()});
}
{
try {
EXPECT_EQ(std::filesystem::is_directory("testtores/testdir"), true);
} catch (...) {
std::cerr << "Empty directory doesn't exist!" << std::endl;
throw;
}
for (int i = 0; i < 257; i++) {
std::ifstream o(std::filesystem::path("testtores") / ("f" + std::to_string(i)), std::ios::binary | std::ios::in);
try {
EXPECT_EQ(o.is_open(), true);
for (int j = 0; j < i; j++) {
char c;
EXPECT_EQ(o.get(c).operator bool(), true);
EXPECT_EQ(static_cast<char>(j % 256), c);
}
} catch (...) {
std::cerr << "Error comparing file " << i << std::endl;
throw;
}
}
}
}
TEST(FullTest, SimpleWithIgnore) {
Cleaner c({"testfrom", "testto", "testtores"});
int aid = -1;
{
std::filesystem::create_directories("testfrom");
for (int i = 0; i < 257; i++) {
std::ofstream o(std::filesystem::path("testfrom") / ("f" + std::to_string(i)), std::ios::binary | std::ios::out | std::ios::trunc);
for (int j = 0; j < i; j++) o.put(static_cast<char>(j % 256));
}
std::filesystem::create_directories("testfrom/testdir");
std::filesystem::create_directories("testfrom/testdir2/testdir3");
std::filesystem::create_directories("testfrom/testdir2/testdir4");
{
std::ofstream file("testfrom/testdir2/.ignore");
file << "hello.txt";
}
{
std::ofstream file("testfrom/testdir2/testdir3/.ignore");
file << ".*\\.txt";
}
{
std::ofstream file("testfrom/testdir2/hello.txt");
file << "hello";
}
{
std::ofstream file("testfrom/testdir2/testdir3/hello.txt");
file << "hello2";
}
{
std::ofstream file("testfrom/testdir2/testdir3/asdf.txt");
file << "asdf1";
}
{
std::ofstream file("testfrom/testdir2/testdir4/asdf.txt");
file << "asdf2";
}
Config conf;
conf.add("repo", "testto").add("from", "testfrom");
auto repo = std::make_unique<FileRepository>(conf);
repo->init();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRun cmd;
cmd.run(Context{&logger, repo.get()});
aid = repo->getObjects(Object::ObjectType::Archive).begin()->second;
}
{
Config conf;
conf.add("repo", "testto").add("aid", std::to_string(aid)).add("to", "testtores");
auto repo = std::make_unique<FileRepository>(conf);
repo->open();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRestore cmd;
cmd.run(Context{&logger, repo.get()});
}
{
EXPECT_EQ(std::filesystem::is_directory("testtores/testdir"), true);
for (int i = 0; i < 257; i++) {
std::ifstream o(std::filesystem::path("testtores") / ("f" + std::to_string(i)), std::ios::binary | std::ios::in);
EXPECT_EQ(o.is_open(), true);
for (int j = 0; j < i; j++) {
char c;
EXPECT_EQ(o.get(c).operator bool(), true);
EXPECT_EQ(static_cast<char>(j % 256), c);
}
}
{
std::ifstream file("testtores/testdir2/.ignore");
std::string s;
file >> s;
EXPECT_EQ(s, "hello.txt");
}
{
std::ifstream file("testtores/testdir2/testdir3/.ignore");
std::string s;
file >> s;
EXPECT_EQ(s, ".*\\.txt");
}
{
std::ifstream file("testtores/testdir2/hello.txt");
EXPECT_EQ(!file, true);
}
{
std::ifstream file("testtores/testdir2/testdir3/hello.txt");
EXPECT_EQ(!file, true);
}
{
std::ifstream file("testtores/testdir2/testdir3/asdf.txt");
EXPECT_EQ(!file, true);
}
{
std::ifstream file("testtores/testdir2/testdir4/asdf.txt");
std::string s;
file >> s;
EXPECT_EQ(s, "asdf2");
}
}
}
TEST(FullTest, SimpleWithCompress) {
Cleaner c({"testfrom", "testto", "testtores"});
int aid = -1;
{
std::filesystem::create_directories("testfrom");
for (int i = 0; i < 257; i++) {
std::ofstream o(std::filesystem::path("testfrom") / ("f" + std::to_string(i)), std::ios::binary | std::ios::out | std::ios::trunc);
for (int j = 0; j < i; j++) o.put(static_cast<char>(j % 256));
}
std::filesystem::create_directories("testfrom/testdir");
Config conf;
conf.add("repo", "testto").add("compression", "zlib").add("from", "testfrom");
auto repo = std::make_unique<FileRepository>(conf);
repo->init();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRun cmd;
cmd.run(Context{&logger, repo.get()});
aid = repo->getObjects(Object::ObjectType::Archive).begin()->second;
}
{
Config conf;
conf.add("repo", "testto").add("aid", std::to_string(aid)).add("to", "testtores");
auto repo = std::make_unique<FileRepository>(conf);
repo->open();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRestore cmd;
cmd.run(Context{&logger, repo.get()});
}
{
EXPECT_EQ(std::filesystem::is_directory("testtores/testdir"), true);
for (int i = 0; i < 257; i++) {
std::ifstream o(std::filesystem::path("testtores") / ("f" + std::to_string(i)), std::ios::binary | std::ios::in);
EXPECT_EQ(o.is_open(), true);
for (int j = 0; j < i; j++) {
char c;
EXPECT_EQ(o.get(c).operator bool(), true);
EXPECT_EQ(static_cast<char>(j % 256), c);
}
}
}
}
TEST(FullTest, SimpleWithCompEnd) {
Cleaner c({"testfrom", "testto", "testtores"});
int aid = -1;
{
std::filesystem::create_directories("testfrom");
for (int i = 0; i < 257; i++) {
std::ofstream o(std::filesystem::path("testfrom") / ("f" + std::to_string(i)), std::ios::binary | std::ios::out | std::ios::trunc);
for (int j = 0; j < i; j++) o.put(static_cast<char>(j % 256));
}
std::filesystem::create_directories("testfrom/testdir");
Config conf;
conf.add("repo", "testto").add("compression", "zlib").add("from", "testfrom").add("encryption", "aes").add("password", "testp").add("salt", "tests");
auto repo = std::make_unique<FileRepository>(conf);
repo->init();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRun cmd;
cmd.run(Context{&logger, repo.get()});
aid = repo->getObjects(Object::ObjectType::Archive).begin()->second;
}
{
Config conf;
conf.add("repo", "testto");
auto repo = std::make_unique<FileRepository>(conf);
bool ok = true;
try {
EXPECT_EQ(repo->open(), false);
ok = false;
} catch (...) {}
EXPECT_EQ(ok, true);
}
{
Config conf;
conf.add("repo", "testto").add("password", "testp").add("aid", std::to_string(aid)).add("to", "testtores");
auto repo = std::make_unique<FileRepository>(conf);
repo->open();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRestore cmd;
cmd.run(Context{&logger, repo.get()});
}
{
EXPECT_EQ(std::filesystem::is_directory("testtores/testdir"), true);
for (int i = 0; i < 257; i++) {
std::ifstream o(std::filesystem::path("testtores") / ("f" + std::to_string(i)), std::ios::binary | std::ios::in);
EXPECT_EQ(o.is_open(), true);
for (int j = 0; j < i; j++) {
char c;
EXPECT_EQ(o.get(c).operator bool(), true);
EXPECT_EQ(static_cast<char>(j % 256), c);
}
}
}
}
TEST(FullTest, Fuzz) {
GTEST_SKIP();
srand(time(nullptr));
std::vector<Config> confs;
Config conf;
conf.add("repo", "testto").add("compression", "none").add("from", "testfrom").add("encryption", "none").add("password", "testp").add("salt", "tests").add("progress", "none");
confs.emplace_back(conf);
conf = Config();
conf.add("repo", "testto").add("compression", "zlib").add("from", "testfrom").add("encryption", "none").add("password", "testp").add("salt", "tests").add("progress", "none");
confs.emplace_back(conf);
conf = Config();
conf.add("repo", "testto").add("compression", "none").add("from", "testfrom").add("encryption", "zlib").add("password", "testp").add("salt", "tests").add("progress", "none");
confs.emplace_back(conf);
conf = Config();
conf.add("repo", "testto").add("compression", "zlib").add("from", "testfrom").add("encryption", "aes").add("password", "testp").add("salt", "tests").add("progress", "none");
confs.emplace_back(conf);
for (auto const &conf: confs) {
for (uint8_t filetobreak = 1; filetobreak <= 15; filetobreak++) {
std::cout << static_cast<int>(filetobreak) << " / 15 tests done" << std::endl;
for (uint8_t cutoff = 1; cutoff < 20; cutoff++) {
Cleaner c({"testfrom", "testto", "testtores"});
int aid = -1;
{
std::filesystem::create_directories("testfrom");
for (int i = 0; i < 2; i++) {
std::ofstream o(std::filesystem::path("testfrom") / ("f" + std::to_string(i)), std::ios::binary | std::ios::out | std::ios::trunc);
for (int j = 0; j < i; j++) o.put(j % 2);
}
auto repo = std::make_unique<FileRepository>(conf);
repo->init();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRun cmd;
cmd.run(Context{&logger, repo.get()});
aid = repo->getObjects(Object::ObjectType::Archive).begin()->second;
}
{
if (filetobreak & 0b00000001) {
for (int i = 0; i < cutoff; i++)
randomChange("testto/1");
if (cutoff > 5)
std::filesystem::resize_file("testto/1", std::filesystem::file_size("testto/1") - cutoff);
}
if (filetobreak & 0b00000010) {
for (int i = 0; i < cutoff; i++)
randomChange("testto/index");
if (cutoff > 5)
std::filesystem::resize_file("testto/index", std::filesystem::file_size("testto/index") - cutoff);
}
if (filetobreak & 0b00000100) {
for (int i = 0; i < cutoff; i++)
randomChange("testto/offsets");
if (cutoff > 5)
std::filesystem::resize_file("testto/offsets", std::filesystem::file_size("testto/offsets") - cutoff);
}
if (filetobreak & 0b00001000) {
for (int i = 0; i < cutoff; i++)
randomChange("testto/info");
if (cutoff > 5)
std::filesystem::resize_file("testto/info", std::filesystem::file_size("testto/info") - cutoff);
}
}
{
bool ok = true;
try {
Config confr = conf;
confr.add("aid", std::to_string(aid)).add("to", "testtores");
auto repo = std::make_unique<FileRepository>(confr);
repo->open();
std::stringstream runnerout;
Logger logger(1, runnerout);
CommandRestore cmd;
cmd.run(Context{&logger, repo.get()});
auto outstr = runnerout.str();
if (outstr.find("Error") == std::string::npos)
ok = false;
} catch (...) {}
EXPECT_EQ(ok, true);
}
}
}
}
}

24
tests/repo/CMakeLists.txt Normal file
View File

@@ -0,0 +1,24 @@
cmake_minimum_required(VERSION 3.22)
add_executable(
FileRepositoryTest
srcs/FileRepositoryTest.cpp
)
target_link_libraries(
FileRepositoryTest PRIVATE
GTest::gtest_main commands utils testUtils repo
)
add_executable(
ChunkTest
srcs/ChunkTest.cpp
)
target_link_libraries(
ChunkTest PRIVATE
GTest::gtest_main commands utils testUtils repo
)
gtest_discover_tests(ChunkTest)
gtest_discover_tests(FileRepositoryTest)

View File

@@ -1,113 +0,0 @@
//
// Created by Stepan Usatiuk on 14.04.2023.
//
#include "ChunkTest.h"
#include "../../src/repo/Serialize.h"
#include "../utils/Cleaner.h"
std::unique_ptr<TestGroup> ChunkTest::operator()() {
auto tg = std::make_unique<TestGroup>("Chunk tests");
tg->addTest(std::make_unique<Test>("De/serialize test", std::function<bool()>([]() {
std::vector<char> s1, s2;
{
std::vector<char> data1{'a', 'b', 'c', 'e'};
Chunk o1(666, {0}, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
Chunk o2(777, {1}, data2);
s1 = Serialize::serialize(o1);
s2 = Serialize::serialize(o2);
}
{
auto s1b = s1.cbegin();
auto s2b = s2.cbegin();
Chunk o1(s1b, s1.cend()), o2(s2b, s2.cend());
std::vector<char> data1{'a', 'b', 'c', 'e'};
Chunk o1e(666, {0}, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
Chunk o2e(777, {1}, data2);
HelpfulAssert<Object::idType>()(o1.id, o1e.id);
HelpfulAssert<Object::idType>()(o2.id, o2e.id);
HelpfulAssert<int>()((int) o1.type, (int) o1e.type);
HelpfulAssert<int>()((int) o2.type, (int) o2e.type);
HelpfulAssert<size_t>()(o1.data.size(), o1e.data.size());
HelpfulAssert<size_t>()(o2.data.size(), o2e.data.size());
for (int i = 0; i < o1.data.size(); i++) {
HelpfulAssert<char>()(o1.data[i], o1e.data[i]);
}
for (int i = 0; i < o2.data.size(); i++) {
HelpfulAssert<char>()(o2.data[i], o2e.data[i]);
}
for (int i = 0; i < o1.md5.size(); i++) {
HelpfulAssert<char>()(o1.md5[i], o1e.md5[i]);
}
for (int i = 0; i < o2.md5.size(); i++) {
HelpfulAssert<char>()(o2.md5[i], o2e.md5[i]);
}
}
return true;
})));
tg->addTest(std::make_unique<Test>("Garbage throw test", std::function<bool()>([]() {
std::vector<char> e{'a', 'b'};
auto eb = e.cbegin();
try {
Chunk o1(eb, e.cend());
} catch (...) {
return true;
}
throw Exception("Object constructed with garbage data!");
})));
tg->addTest(std::make_unique<Test>("Garbage throw test2", std::function<bool()>([]() {
std::vector<char> e{'s', 'e', 'm', 'b', 'a', 'a'};
auto eb = e.cbegin();
try {
Chunk o1(eb, e.cend());
} catch (...) {
return true;
}
throw Exception("Object constructed with garbage data!");
})));
tg->addTest(std::make_unique<Test>("Garbage throw test3", std::function<bool()>([]() {
std::vector<char> s1, s2;
{
std::vector<char> data1{'a', 'b', 'c', 'e'};
Chunk o1(666, {0}, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
Chunk o2(777, {1}, data2);
s1 = Serialize::serialize(o1);
s2 = Serialize::serialize(o2);
}
{
s1.resize(s1.size() - 1);
s2.resize(s1.size() - 2);
bool fail = false;
try {
Chunk o1 = Serialize::deserialize<Chunk>(s1);
fail = true;
} catch (...) {
}
try {
Chunk o2 = Serialize::deserialize<Chunk>(s2);
fail = true;
} catch (...) {
}
if (fail)
throw Exception("Object constructed with garbage data!");
}
return true;
})));
return tg;
}

View File

@@ -1,21 +0,0 @@
//
// Created by Stepan Usatiuk on 14.04.2023.
//
#ifndef SEMBACKUP_CHUNKTEST_H
#define SEMBACKUP_CHUNKTEST_H
#include <fstream>
#include <iostream>
#include <vector>
#include "../../src/repo/objects/Chunk.h"
#include "../utils/TestGroupGenerator.h"
class ChunkTest : public TestGroupGenerator {
public:
std::unique_ptr<TestGroup> operator()() override;
};
#endif//SEMBACKUP_CHUNKTEST_H

View File

@@ -1,301 +0,0 @@
//
// Created by Stepan Usatiuk on 14.04.2023.
//
#include "FileRepositoryTest.h"
std::unique_ptr<TestGroup> FileRepositoryTest::operator()() {
auto tg = std::make_unique<TestGroup>("FileRepository tests");
tg->addTest(std::make_unique<Test>("De/serialize test", std::function<bool()>([]() {
Cleaner c({"testrepo"});
{
Config conf;
conf.add("repo", "testrepo");
FileRepository repo(conf);
repo.init();
std::vector<char>
data1{'a', 'b', 'c', 'e'};
std::string o1k(16, '\0');
std::string o2k(16, '\0');
o2k[0] = 1;
o2k[1] = 2;
Chunk o1(666, o1k, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', static_cast<char>(255)};
Chunk o2(777, o2k, data2);
repo.putObject(o1);
repo.putObject(o2);
HelpfulAssert<Object::idType>()(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
HelpfulAssert<Object::idType>()(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
}
{
Config conf;
conf.add("repo", "testrepo");
FileRepository repo(conf);
repo.open();
std::string o1k(16, '\0');
std::string o2k(16, '\0');
o2k[0] = 1;
o2k[1] = 2;
HelpfulAssert<Object::idType>()(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
HelpfulAssert<Object::idType>()(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
auto o1o = repo.getObject(666);
auto o2o = repo.getObject(777);
auto o1ob = o1o.cbegin();
auto o2ob = o2o.cbegin();
Chunk o1(o1ob, o1o.cend()), o2(o2ob, o2o.cend());
std::vector<char> data1{'a', 'b', 'c', 'e'};
Chunk o1e(666, o1k, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', static_cast<char>(255)};
Chunk o2e(777, o2k, data2);
HelpfulAssert<Object::idType>()(o1.id, o1e.id);
HelpfulAssert<Object::idType>()(o2.id, o2e.id);
HelpfulAssert<int>()((int) o1.type, (int) o1e.type);
HelpfulAssert<int>()((int) o2.type, (int) o2e.type);
auto o1d = o1.data;
auto o1ed = o1e.data;
auto o2d = o2.data;
auto o2ed = o2e.data;
HelpfulAssert<size_t>()(o1.data.size(), o1e.data.size());
HelpfulAssert<size_t>()(o2.data.size(), o2e.data.size());
for (int i = 0; i < o1.data.size(); i++) {
HelpfulAssert<char>()(o1.data[i], o1e.data[i]);
}
for (int i = 0; i < o2.data.size(); i++) {
HelpfulAssert<char>()(o2.data[i], o2e.data[i]);
}
}
return true;
})));
tg->addTest(std::make_unique<Test>("De/serialize with sync/read filter", std::function<bool()>([]() {
Cleaner c({"testrepo"});
{
Config conf;
conf.add("repo", "testrepo")
.add("compression", "shiftC")
.add("compression-level", "1")
.add("encryption", "shiftE")
.add("password", "\a")
.add("salt", "a");
FileRepository repo(conf);
repo.init();
std::string o1k(16, '\0');
std::string o2k(16, '\0');
o2k[0] = 1;
o2k[1] = 2;
std::vector<char>
data1{'a', 'b', 'c', 'e'};
Chunk o1(666, o1k, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
Chunk o2(777, o2k, data2);
repo.putObject(o1);
repo.putObject(o2);
HelpfulAssert<Object::idType>()(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
HelpfulAssert<Object::idType>()(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
}
{
Config conf;
conf.add("repo", "testrepo")
.add("compression", "shiftC")
.add("compression-level", "1")
.add("encryption", "shiftE")
.add("password", "\b")
.add("salt", "a");
FileRepository repo(conf);
bool err = false;
try {
repo.open();
err = true;
} catch (...) {}
try {
auto o1o = repo.getObject(666);
auto o1ob = o1o.cbegin();
Chunk o1(o1ob, o1o.cend());
err = true;
} catch (...) {}
try {
auto o2o = repo.getObject(777);
auto o2ob = o2o.cbegin();
Chunk o2(o2ob, o2o.cend());
err = true;
} catch (...) {}
if (err)
throw Exception("Object constructed with garbage data!");
}
{
Config conf;
conf.add("repo", "testrepo")
.add("compression", "shiftC")
.add("compression-level", "1")
.add("encryption", "shiftE")
.add("password", "\a")
.add("salt", "a");
FileRepository repo(conf);
repo.open();
std::string o1k(16, '\0');
std::string o2k(16, '\0');
o2k[0] = 1;
o2k[1] = 2;
HelpfulAssert<Object::idType>()(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
HelpfulAssert<Object::idType>()(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
auto o1o = repo.getObject(666);
auto o2o = repo.getObject(777);
auto o1ob = o1o.cbegin();
auto o2ob = o2o.cbegin();
Chunk o1(o1ob, o1o.cend()), o2(o2ob, o2o.cend());
std::vector<char> data1{'a', 'b', 'c', 'e'};
Chunk o1e(666, o1k, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
Chunk o2e(777, o2k, data2);
HelpfulAssert<Object::idType>()(o1.id, o1e.id);
HelpfulAssert<Object::idType>()(o2.id, o2e.id);
HelpfulAssert<int>()((int) o1.type, (int) o1e.type);
HelpfulAssert<int>()((int) o2.type, (int) o2e.type);
auto o1d = o1.data;
auto o1ed = o1e.data;
auto o2d = o2.data;
auto o2ed = o2e.data;
HelpfulAssert<size_t>()(o1.data.size(), o1e.data.size());
HelpfulAssert<size_t>()(o2.data.size(), o2e.data.size());
for (int i = 0; i < o1.data.size(); i++) {
HelpfulAssert<char>()(o1.data[i], o1e.data[i]);
}
for (int i = 0; i < o2.data.size(); i++) {
HelpfulAssert<char>()(o2.data[i], o2e.data[i]);
}
}
return true;
})));
tg->addTest(std::make_unique<Test>("IDs test (disabled)", std::function<bool()>([]() {
return true;
Cleaner c({"testrepo"});
{
Config conf;
conf.add("repo", "testrepo");
FileRepository repo(conf);
repo.init();
std::string o1k(16, '\0');
std::string o2k(16, '\0');
o2k[0] = 1;
std::vector<char>
data1{'a', 'b', 'c', 'e'};
Chunk o1(repo.getId(), o1k, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
Chunk o2(repo.getId(), o2k, data2);
HelpfulAssert<int>()(o1.id, 1);
HelpfulAssert<int>()(o2.id, 2);
repo.putObject(o1);
repo.putObject(o2);
HelpfulAssert<Object::idType>()(repo.getObjectId(Object::ObjectType::Chunk, o1k), 1);
HelpfulAssert<Object::idType>()(repo.getObjectId(Object::ObjectType::Chunk, o2k), 2);
}
{
Config conf;
conf.add("repo", "testrepo");
FileRepository repo(conf);
repo.open();
auto o1o = repo.getObject(1);
auto o2o = repo.getObject(2);
auto o1ob = o1o.cbegin();
auto o2ob = o2o.cbegin();
Chunk o1(o1ob, o1o.cend()), o2(o2ob, o2o.cend());
std::string o1k(16, '\0');
std::string o2k(16, '\0');
o2k[0] = 1;
std::vector<char> data1{'a', 'b', 'c', 'e'};
Chunk o1e(1, o1k, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
Chunk o2e(2, o2k, data2);
HelpfulAssert<Object::idType>()(o1.id, o1e.id);
HelpfulAssert<Object::idType>()(o2.id, o2e.id);
HelpfulAssert<int>()((int) o1.type, (int) o1e.type);
HelpfulAssert<int>()((int) o2.type, (int) o2e.type);
auto o1d = o1.data;
auto o1ed = o1e.data;
auto o2d = o2.data;
auto o2ed = o2e.data;
HelpfulAssert<size_t>()(o1.data.size(), o1e.data.size());
HelpfulAssert<size_t>()(o2.data.size(), o2e.data.size());
for (int i = 0; i < o1.data.size(); i++) {
HelpfulAssert<char>()(o1.data[i], o1e.data[i]);
}
for (int i = 0; i < o2.data.size(); i++) {
HelpfulAssert<char>()(o2.data[i], o2e.data[i]);
}
HelpfulAssert<Object::idType>()(repo.getObjectId(Object::ObjectType::Chunk, o1k), 1);
HelpfulAssert<Object::idType>()(repo.getObjectId(Object::ObjectType::Chunk, o2k), 2);
repo.deleteObject(o1);
}
{
Config conf;
conf.add("repo", "testrepo");
FileRepository repo(conf);
repo.open();
std::string o2k(16, '\0');
o2k[0] = 1;
HelpfulAssert<Object::idType>()(repo.getObjectId(Object::ObjectType::Chunk, o2k), 2);
auto id = repo.getId();
HelpfulAssert<int>()(id, 1);
std::vector<char>
data1{'a', 'b', 'c', 'e'};
Chunk o1(id, o2k, data1);
HelpfulAssert<int>()(repo.getId(), 3);
}
return true;
})));
return tg;
}

View File

@@ -1,24 +0,0 @@
//
// Created by Stepan Usatiuk on 14.04.2023.
//
#ifndef SEMBACKUP_FILEREPOSITORYTEST_H
#define SEMBACKUP_FILEREPOSITORYTEST_H
#include <fstream>
#include <iostream>
#include <vector>
#include "../../src/repo/FileRepository.h"
#include "../../src/repo/objects/Chunk.h"
#include "../utils/Cleaner.h"
#include "../utils/TestGroupGenerator.h"
class FileRepositoryTest : public TestGroupGenerator {
public:
std::unique_ptr<TestGroup> operator()() override;
};
#endif//SEMBACKUP_FILEREPOSITORYTEST_H

View File

@@ -0,0 +1,108 @@
//
// Created by Stepan Usatiuk on 14.04.2023.
//
#include <gtest/gtest.h>
#include "Cleaner.h"
#include "Serialize.h"
#include "objects/Chunk.h"
TEST(Chunk, Deserialize) {
std::vector<char> s1, s2;
{
std::vector<char> data1{'a', 'b', 'c', 'e'};
Chunk o1(666, {0}, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
Chunk o2(777, {1}, data2);
s1 = Serialize::serialize(o1);
s2 = Serialize::serialize(o2);
}
{
auto s1b = s1.cbegin();
auto s2b = s2.cbegin();
Chunk o1(s1b, s1.cend()), o2(s2b, s2.cend());
std::vector<char> data1{'a', 'b', 'c', 'e'};
Chunk o1e(666, {0}, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
Chunk o2e(777, {1}, data2);
EXPECT_EQ(o1.id, o1e.id);
EXPECT_EQ(o2.id, o2e.id);
EXPECT_EQ((int) o1.type, (int) o1e.type);
EXPECT_EQ((int) o2.type, (int) o2e.type);
EXPECT_EQ(o1.data.size(), o1e.data.size());
EXPECT_EQ(o2.data.size(), o2e.data.size());
for (int i = 0; i < o1.data.size(); i++) {
EXPECT_EQ(o1.data[i], o1e.data[i]);
}
for (int i = 0; i < o2.data.size(); i++) {
EXPECT_EQ(o2.data[i], o2e.data[i]);
}
for (int i = 0; i < o1.md5.size(); i++) {
EXPECT_EQ(o1.md5[i], o1e.md5[i]);
}
for (int i = 0; i < o2.md5.size(); i++) {
EXPECT_EQ(o2.md5[i], o2e.md5[i]);
}
}
}
TEST(Chunk, Garbage) {
std::vector<char> e{'a', 'b'};
auto eb = e.cbegin();
try {
Chunk o1(eb, e.cend());
} catch (...) {
return;
}
FAIL() << "Object constructed with garbage data!";
}
TEST(Chunk, Garbage2) {
std::vector<char> e{'s', 'e', 'm', 'b', 'a', 'a'};
auto eb = e.cbegin();
try {
Chunk o1(eb, e.cend());
} catch (...) {
return;
}
FAIL() << "Object constructed with garbage data!";
}
TEST(Chunk, Garbage3) {
std::vector<char> s1, s2;
{
std::vector<char> data1{'a', 'b', 'c', 'e'};
Chunk o1(666, {0}, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
Chunk o2(777, {1}, data2);
s1 = Serialize::serialize(o1);
s2 = Serialize::serialize(o2);
}
{
s1.resize(s1.size() - 1);
s2.resize(s1.size() - 2);
bool fail = false;
try {
Chunk o1 = Serialize::deserialize<Chunk>(s1);
fail = true;
} catch (...) {
}
try {
Chunk o2 = Serialize::deserialize<Chunk>(s2);
fail = true;
} catch (...) {
}
if (fail)
FAIL() << "Object constructed with garbage data!";
}
}

View File

@@ -0,0 +1,295 @@
//
// Created by Stepan Usatiuk on 14.04.2023.
//
#include <gtest/gtest.h>
#include "Cleaner.h"
#include "Exception.h"
#include "FileRepository.h"
#include "objects/Chunk.h"
TEST(FileRepository, Deserialize) {
Cleaner c({"testrepo"});
{
Config conf;
conf.add("repo", "testrepo");
FileRepository repo(conf);
repo.init();
std::vector<char>
data1{'a', 'b', 'c', 'e'};
std::string o1k(16, '\0');
std::string o2k(16, '\0');
o2k[0] = 1;
o2k[1] = 2;
Chunk o1(666, o1k, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', static_cast<char>(255)};
Chunk o2(777, o2k, data2);
repo.putObject(o1);
repo.putObject(o2);
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
}
{
Config conf;
conf.add("repo", "testrepo");
FileRepository repo(conf);
repo.open();
std::string o1k(16, '\0');
std::string o2k(16, '\0');
o2k[0] = 1;
o2k[1] = 2;
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
auto o1o = repo.getObject(666);
auto o2o = repo.getObject(777);
auto o1ob = o1o.cbegin();
auto o2ob = o2o.cbegin();
Chunk o1(o1ob, o1o.cend()), o2(o2ob, o2o.cend());
std::vector<char> data1{'a', 'b', 'c', 'e'};
Chunk o1e(666, o1k, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', static_cast<char>(255)};
Chunk o2e(777, o2k, data2);
EXPECT_EQ(o1.id, o1e.id);
EXPECT_EQ(o2.id, o2e.id);
EXPECT_EQ((int) o1.type, (int) o1e.type);
EXPECT_EQ((int) o2.type, (int) o2e.type);
auto o1d = o1.data;
auto o1ed = o1e.data;
auto o2d = o2.data;
auto o2ed = o2e.data;
EXPECT_EQ(o1.data.size(), o1e.data.size());
EXPECT_EQ(o2.data.size(), o2e.data.size());
for (int i = 0; i < o1.data.size(); i++) {
EXPECT_EQ(o1.data[i], o1e.data[i]);
}
for (int i = 0; i < o2.data.size(); i++) {
EXPECT_EQ(o2.data[i], o2e.data[i]);
}
}
}
TEST(FileRepository, Filters) {
Cleaner c({"testrepo"});
{
Config conf;
conf.add("repo", "testrepo")
.add("compression", "shiftC")
.add("compression-level", "1")
.add("encryption", "shiftE")
.add("password", "\a")
.add("salt", "a");
FileRepository repo(conf);
repo.init();
std::string o1k(16, '\0');
std::string o2k(16, '\0');
o2k[0] = 1;
o2k[1] = 2;
std::vector<char>
data1{'a', 'b', 'c', 'e'};
Chunk o1(666, o1k, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
Chunk o2(777, o2k, data2);
repo.putObject(o1);
repo.putObject(o2);
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
}
{
Config conf;
conf.add("repo", "testrepo")
.add("compression", "shiftC")
.add("compression-level", "1")
.add("encryption", "shiftE")
.add("password", "\b")
.add("salt", "a");
FileRepository repo(conf);
bool err = false;
try {
repo.open();
err = true;
} catch (...) {}
try {
auto o1o = repo.getObject(666);
auto o1ob = o1o.cbegin();
Chunk o1(o1ob, o1o.cend());
err = true;
} catch (...) {}
try {
auto o2o = repo.getObject(777);
auto o2ob = o2o.cbegin();
Chunk o2(o2ob, o2o.cend());
err = true;
} catch (...) {}
if (err)
throw Exception("Object constructed with garbage data!");
}
{
Config conf;
conf.add("repo", "testrepo")
.add("compression", "shiftC")
.add("compression-level", "1")
.add("encryption", "shiftE")
.add("password", "\a")
.add("salt", "a");
FileRepository repo(conf);
repo.open();
std::string o1k(16, '\0');
std::string o2k(16, '\0');
o2k[0] = 1;
o2k[1] = 2;
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 666);
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 777);
auto o1o = repo.getObject(666);
auto o2o = repo.getObject(777);
auto o1ob = o1o.cbegin();
auto o2ob = o2o.cbegin();
Chunk o1(o1ob, o1o.cend()), o2(o2ob, o2o.cend());
std::vector<char> data1{'a', 'b', 'c', 'e'};
Chunk o1e(666, o1k, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
Chunk o2e(777, o2k, data2);
EXPECT_EQ(o1.id, o1e.id);
EXPECT_EQ(o2.id, o2e.id);
EXPECT_EQ((int) o1.type, (int) o1e.type);
EXPECT_EQ((int) o2.type, (int) o2e.type);
auto o1d = o1.data;
auto o1ed = o1e.data;
auto o2d = o2.data;
auto o2ed = o2e.data;
EXPECT_EQ(o1.data.size(), o1e.data.size());
EXPECT_EQ(o2.data.size(), o2e.data.size());
for (int i = 0; i < o1.data.size(); i++) {
EXPECT_EQ(o1.data[i], o1e.data[i]);
}
for (int i = 0; i < o2.data.size(); i++) {
EXPECT_EQ(o2.data[i], o2e.data[i]);
}
}
}
TEST(FileRepository, IDsDisabled) {
GTEST_SKIP();
Cleaner c({"testrepo"});
{
Config conf;
conf.add("repo", "testrepo");
FileRepository repo(conf);
repo.init();
std::string o1k(16, '\0');
std::string o2k(16, '\0');
o2k[0] = 1;
std::vector<char>
data1{'a', 'b', 'c', 'e'};
Chunk o1(repo.getId(), o1k, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
Chunk o2(repo.getId(), o2k, data2);
EXPECT_EQ(o1.id, 1);
EXPECT_EQ(o2.id, 2);
repo.putObject(o1);
repo.putObject(o2);
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 1);
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 2);
}
{
Config conf;
conf.add("repo", "testrepo");
FileRepository repo(conf);
repo.open();
auto o1o = repo.getObject(1);
auto o2o = repo.getObject(2);
auto o1ob = o1o.cbegin();
auto o2ob = o2o.cbegin();
Chunk o1(o1ob, o1o.cend()), o2(o2ob, o2o.cend());
std::string o1k(16, '\0');
std::string o2k(16, '\0');
o2k[0] = 1;
std::vector<char> data1{'a', 'b', 'c', 'e'};
Chunk o1e(1, o1k, data1);
std::vector<char> data2{'q', 'w', 'e', 'r', 'b'};
Chunk o2e(2, o2k, data2);
EXPECT_EQ(o1.id, o1e.id);
EXPECT_EQ(o2.id, o2e.id);
EXPECT_EQ((int) o1.type, (int) o1e.type);
EXPECT_EQ((int) o2.type, (int) o2e.type);
auto o1d = o1.data;
auto o1ed = o1e.data;
auto o2d = o2.data;
auto o2ed = o2e.data;
EXPECT_EQ(o1.data.size(), o1e.data.size());
EXPECT_EQ(o2.data.size(), o2e.data.size());
for (int i = 0; i < o1.data.size(); i++) {
EXPECT_EQ(o1.data[i], o1e.data[i]);
}
for (int i = 0; i < o2.data.size(); i++) {
EXPECT_EQ(o2.data[i], o2e.data[i]);
}
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o1k), 1);
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 2);
repo.deleteObject(o1);
}
{
Config conf;
conf.add("repo", "testrepo");
FileRepository repo(conf);
repo.open();
std::string o2k(16, '\0');
o2k[0] = 1;
EXPECT_EQ(repo.getObjectId(Object::ObjectType::Chunk, o2k), 2);
auto id = repo.getId();
EXPECT_EQ(id, 1);
std::vector<char>
data1{'a', 'b', 'c', 'e'};
Chunk o1(id, o2k, data1);
EXPECT_EQ(repo.getId(), 3);
}
}

View File

@@ -1,34 +0,0 @@
//
// Created by Stepan Usatiuk on 13.04.2023.
//
#include <memory>
#include <vector>
#include "BuzhashTest.h"
#include "CLITestWrapper.h"
#include "crypto/AESTest.h"
#include "crypto/MD5Test.h"
#include "fulltests/FullTest.h"
#include "repo/ChunkTest.h"
#include "repo/FileRepositoryTest.h"
#include "utils/HelpfulAssertTest.h"
int main() {
std::vector<std::unique_ptr<Runnable>> tests{};
tests.emplace_back(HelpfulAssertTest()());
tests.emplace_back(MD5Test()());
tests.emplace_back(AESTest()());
tests.emplace_back(ChunkTest()());
tests.emplace_back(FileRepositoryTest()());
tests.emplace_back(BuzhashTest()());
tests.emplace_back(CLITestWrapper()());
tests.emplace_back(FullTest()());
bool ok = true;
for (const auto &t: tests) {
ok = t->run(std::cout) && ok;
}
return ok ? 0 : -1;
}

View File

@@ -0,0 +1,5 @@
cmake_minimum_required(VERSION 3.22)
add_library(testUtils srcs/Cleaner.cpp)
target_include_directories(testUtils PUBLIC includes)

View File

@@ -1,43 +0,0 @@
//
// Created by Stepan Usatiuk on 13.04.2023.
//
#ifndef SEMBACKUP_HELPFULASSERT_H
#define SEMBACKUP_HELPFULASSERT_H
#include <functional>
#include <iostream>
#include <ostream>
#include <sstream>
#include <utility>
#include "../../src/Exception.h"
template<typename T, typename comp = std::equal_to<>>
class HelpfulAssert {
public:
bool operator()(const T &lhs, const T &rhs) {
if (!comp()(lhs, rhs)) {
std::stringstream out;
if constexpr (has_print_op<T>::value) {
out << "Expected lhs to compare to " << rhs << std::endl;
out << "But lhs is " << lhs << std::endl;
} else {
out << "Error comparing!" << std::endl;
}
throw Exception(out.str());
}
return true;
}
private:
template<typename, typename = void>
struct has_print_op : std::false_type {};
template<typename E>
struct has_print_op<E, std::void_t<decltype(std::declval<std::ostream>() << std::declval<E>())>> : std::true_type {};
};
#endif//SEMBACKUP_HELPFULASSERT_H

View File

@@ -1,65 +0,0 @@
//
// Created by Stepan Usatiuk on 13.04.2023.
//
#include "HelpfulAssertTest.h"
std::unique_ptr<TestGroup> HelpfulAssertTest::operator()() {
auto tg = std::make_unique<TestGroup>("HelpfulAssert tests");
tg->addTest(std::make_unique<Test>("Equal test", std::function<bool()>([]() {
HelpfulAssert<int>()(1, 1);
HelpfulAssert<std::string>()("hello", "hello");
try {
HelpfulAssert<std::string>()("hello", "hello2");
} catch (const Exception &e) {
if (std::string_view(e.what()).find("Expected lhs to compare to hello2\nBut lhs is hello\n") == std::string_view::npos)
throw Exception("HelpfulAssert text is wrong");
} catch (...) {
throw Exception("HelpfulAssert throws wrong exception");
}
try {
HelpfulAssert<int>()(1, 2);
} catch (const Exception &e) {
if (std::string_view(e.what()).find("Expected lhs to compare to 2\nBut lhs is 1\n") == std::string_view::npos)
throw Exception("HelpfulAssert text is wrong");
} catch (...) {
throw Exception("HelpfulAssert throws wrong exception");
}
return true;
})));
tg->addTest(std::make_unique<Test>("Greater than test", std::function<bool()>([]() {
HelpfulAssert<int, std::greater<>>()(2, 1);
try {
HelpfulAssert<int, std::greater<>>()(1, 2);
} catch (const Exception &e) {
if (std::string_view(e.what()).find("Expected lhs to compare to 2\nBut lhs is 1\n") == std::string_view::npos)
throw Exception("HelpfulAssert text is wrong");
} catch (...) {
throw Exception("HelpfulAssert throws wrong exception");
}
return true;
})));
tg->addTest(std::make_unique<Test>("Less than test", std::function<bool()>([]() {
HelpfulAssert<int, std::less<>>()(1, 2);
try {
HelpfulAssert<int, std::less<>>()(2, 1);
} catch (const Exception &e) {
if (std::string_view(e.what()).find("Expected lhs to compare to 1\nBut lhs is 2\n") == std::string_view::npos)
throw Exception("HelpfulAssert text is wrong");
} catch (...) {
throw Exception("HelpfulAssert throws wrong exception");
}
return true;
})));
return tg;
}

View File

@@ -1,16 +0,0 @@
//
// Created by Stepan Usatiuk on 13.04.2023.
//
#ifndef SEMBACKUP_HELPFULASSERTTEST_H
#define SEMBACKUP_HELPFULASSERTTEST_H
#include "TestGroupGenerator.h"
class HelpfulAssertTest : public TestGroupGenerator {
public:
std::unique_ptr<TestGroup> operator()() override;
};
#endif//SEMBACKUP_HELPFULASSERTTEST_H

View File

@@ -1,13 +0,0 @@
//
// Created by Stepan Usatiuk on 13.04.2023.
//
#include "Runnable.h"
Runnable::Runnable(std::string name) : name(std::move(name)) {}
std::string Runnable::getName() {
return name;
}
Runnable::~Runnable() = default;

View File

@@ -1,26 +0,0 @@
//
// Created by Stepan Usatiuk on 13.04.2023.
//
#ifndef SEMBACKUP_RUNNABLE_H
#define SEMBACKUP_RUNNABLE_H
#include <iostream>
#include <string>
class Runnable {
public:
Runnable(std::string name);
virtual bool run(std::ostream &out) = 0;
virtual ~Runnable();
std::string getName();
protected:
std::string name;
};
#endif//SEMBACKUP_RUNNABLE_H

View File

@@ -1,16 +0,0 @@
//
// Created by Stepan Usatiuk on 13.04.2023.
//
#include "Test.h"
#include <utility>
Test::Test(std::string name, std::function<bool()> test)
: Runnable(std::move(name)), test(std::move(test)) {}
bool Test::run(std::ostream &out) {
return test();
}
Test::~Test() = default;

View File

@@ -1,25 +0,0 @@
//
// Created by Stepan Usatiuk on 13.04.2023.
//
#ifndef SEMBACKUP_TEST_H
#define SEMBACKUP_TEST_H
#include <functional>
#include "Runnable.h"
class Test : public Runnable {
public:
Test(std::string name, std::function<bool()> test);
bool run(std::ostream &out) override;
~Test() override;
private:
std::function<bool()> test;
};
#endif//SEMBACKUP_TEST_H

View File

@@ -1,31 +0,0 @@
//
// Created by Stepan Usatiuk on 13.04.2023.
//
#include "TestGroup.h"
TestGroup::TestGroup(std::string name) : Runnable(std::move(name)) {}
bool TestGroup::run(std::ostream &out) {
bool ok = true;
out << "Running test group " << getName() << std::endl;
for (auto const &p: tests) {
out << " Running " << p->getName() << " ";
try {
p->run(out);
out << "OK";
} catch (const std::exception &e) {
ok = false;
out << "ERROR" << std::endl;
out << e.what();
}
out << std::endl;
}
return ok;
}
void TestGroup::addTest(std::unique_ptr<Runnable> &&test) {
tests.emplace_back(std::move(test));
}
TestGroup::~TestGroup() = default;

View File

@@ -1,28 +0,0 @@
//
// Created by Stepan Usatiuk on 13.04.2023.
//
#ifndef SEMBACKUP_TESTGROUP_H
#define SEMBACKUP_TESTGROUP_H
#include <memory>
#include <vector>
#include "Runnable.h"
class TestGroup : public Runnable {
public:
TestGroup(std::string name);
bool run(std::ostream &out) override;
void addTest(std::unique_ptr<Runnable> &&test);
~TestGroup() override;
private:
std::vector<std::unique_ptr<Runnable>> tests;
};
#endif//SEMBACKUP_TESTGROUP_H

View File

@@ -1,23 +0,0 @@
//
// Created by Stepan Usatiuk on 13.04.2023.
//
#ifndef SEMBACKUP_TESTGROUPGENERATOR_H
#define SEMBACKUP_TESTGROUPGENERATOR_H
#include <cassert>
#include <functional>
#include <memory>
#include <sstream>
#include "HelpfulAssert.h"
#include "Runnable.h"
#include "Test.h"
#include "TestGroup.h"
class TestGroupGenerator {
public:
virtual std::unique_ptr<TestGroup> operator()() = 0;
};
#endif//SEMBACKUP_TESTGROUPGENERATOR_H

View File

@@ -2,13 +2,14 @@
// Created by Stepan Usatiuk on 14.04.2023.
//
#include "Cleaner.h"
#include "../includes/Cleaner.h"
Cleaner::Cleaner(std::vector<std::filesystem::path> toClean) : toClean(std::move(toClean)) {
for (const auto &p: this->toClean) {
std::filesystem::remove_all(p);
}
}
Cleaner::~Cleaner() {
for (const auto &p: toClean) {
std::filesystem::remove_all(p);