Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion tdd_intro/homework/07_filecopier/07_filecopier.pro
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@ CONFIG -= app_bundle
CONFIG -= qt

SOURCES += \
test.cpp
test.cpp \
FakeFileSystem.cpp

HEADERS += \
FakeFileSystem.h

144 changes: 144 additions & 0 deletions tdd_intro/homework/07_filecopier/FakeFileSystem.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#include "FakeFileSystem.h"
#include <iterator>

FakeFileSystem::FakeFileSystem(const FileSystemObjects &rootObjects)
: m_root(root.string(), rootObjects)
{ }

std::set<std::string> FakeFileSystem::GetChildren(const path &dir)
{
const auto& fsos = GoTo(dir).GetChildren();
std::set<std::string> children;
std::transform(fsos.begin(), fsos.end(), std::inserter(children, children.begin()), [](const auto& fso) { return fso.GetName(); });
return children;
}

bool FakeFileSystem::IsDir(const path &obj)
{
return GoTo(obj).IsDir();
}

void FakeFileSystem::MakeDir(const path &dir)
{
GoToDir(dir.parent_path()).AddChild(Folder(dir.filename().string()));
}

void FakeFileSystem::CopyFile(const path &src, const path &dst)
{
src; // unused
CreateFile(dst);
}

bool FakeFileSystem::FileExists(const path &file)
{
auto fso = GoToSafe(file);
return fso != nullptr && !fso->IsDir();
}

bool FakeFileSystem::DirExists(const path &dir)
{
auto fso = GoToSafe(dir);
return fso != nullptr && fso->IsDir();
}

void FakeFileSystem::CreateFile(const path &file)
{
GoToDir(file.parent_path()).AddChild(File(file.filename().string()));
}

FileSystemObject &FakeFileSystem::GoTo(const path &obj)
{
FileSystemObject* current = &m_root;
path::iterator it = obj.begin();
if (it == obj.end())
{
throw std::runtime_error("Path is empty");
}

for (++it; it != obj.end(); ++it)
{
auto child = std::find_if(current->GetChildren().begin(), current->GetChildren().end(), [&it](const auto& fso)
{ return fso.GetName() == it->string(); }
);
if (child == current->GetChildren().end())
{
throw std::runtime_error("Path does not exist");
}
current = (FileSystemObject*)&(*child);
}
return *current;
}

Folder &FakeFileSystem::GoToDir(const path &dir)
{
auto& target = GoTo(dir);
if (!target.IsDir())
{
throw std::runtime_error("Target path is not a directory");
}
return (Folder&)target;
}

FileSystemObject *FakeFileSystem::GoToSafe(const path &path)
{
FileSystemObject* fso = nullptr;
try
{
fso = &GoTo(path);
}
catch(const std::exception&) { }
return fso;
}

FileSystemObject::FileSystemObject(const std::string& name, bool isDir)
: name(name)
, isDir(isDir)
{ }

FileSystemObject::FileSystemObject(const std::string &name, const FileSystemObjects &children)
: name(name)
, children(children)
, isDir(true)
{ }

const bool FileSystemObject::operator==(const FileSystemObject &other) const
{
return name == other.name;
}

const bool FileSystemObject::operator!=(const FileSystemObject &other) const
{
return !operator==(other);
}

const bool FileSystemObject::operator<(const FileSystemObject &other) const
{
return name < other.name;
}

const std::string &FileSystemObject::GetName() const
{
return name;
}

const FileSystemObjects &FileSystemObject::GetChildren() const
{
return children;
}

bool FileSystemObject::IsDir() const
{
return isDir;
}

void Folder::AddChild(const FileSystemObject &child, bool overwrite /*= false*/)
{
FileSystemObjects::iterator existant = std::find_if(children.begin(), children.end(), [&child](const auto& fso)
{ return fso.GetName() == child.GetName(); }
);
if (existant != children.end() && overwrite)
{
throw std::runtime_error("Child with specified name is already exist");
}
children.insert(child);
}
88 changes: 88 additions & 0 deletions tdd_intro/homework/07_filecopier/FakeFileSystem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include <set>
#include <filesystem>
namespace std
{
using namespace experimental; // for filesystem support
}

using path = std::filesystem::path;
static path::value_type separator = path::preferred_separator;
static path root = std::basic_string<path::value_type>(1, separator);

class IFileSystem
{
public:
virtual ~IFileSystem() { }
virtual std::set<std::string> GetChildren(const path& dir) = 0;
virtual bool IsDir(const path& obj) = 0;

virtual void MakeDir(const path& dir) = 0;
virtual void CopyFile(const path& src, const path& dst) = 0;

virtual bool FileExists(const path& file) = 0;
virtual bool DirExists(const path& dir) = 0;
};

class FileSystemObject;
using FileSystemObjects = std::set<FileSystemObject>;
class FileSystemObject
{
public:
FileSystemObject(const std::string& name, bool isDir);
FileSystemObject(const std::string& name, const FileSystemObjects& children);

bool const operator==(const FileSystemObject& other) const;
bool const operator!=(const FileSystemObject& other) const;
bool const operator<(const FileSystemObject& other) const;

const std::string& GetName() const;
const FileSystemObjects& GetChildren() const;
bool IsDir() const;

protected:
std::string name;
FileSystemObjects children;

private:
bool isDir = true;
};

class File : public FileSystemObject
{
public:
explicit File(const std::string& name): FileSystemObject(name, false) { }
};

class Folder : public FileSystemObject
{
public:
explicit Folder(const std::string& name) : FileSystemObject(name, true) { }
Folder(const std::string& name, const FileSystemObjects& children) : FileSystemObject(name, children) { }
void AddChild(const FileSystemObject& child, bool overwrite = false);
};

class FakeFileSystem: public IFileSystem
{
public:
explicit FakeFileSystem(const FileSystemObjects& rootObjects = { });

virtual std::set<std::string> GetChildren(const path& dir);
virtual bool IsDir(const path& obj);

virtual void MakeDir(const path& dir);
virtual void CopyFile(const path& src, const path& dst);

virtual bool FileExists(const path& file);
virtual bool DirExists(const path& dir);

private:
void CreateFile(const path& file);
void CreateDir(const path& dir);

FileSystemObject& GoTo(const path& path);
Folder &GoToDir(const path& dir);
FileSystemObject* GoToSafe(const path& path);

private:
FileSystemObject m_root;
};
84 changes: 84 additions & 0 deletions tdd_intro/homework/07_filecopier/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,90 @@ You don't need to test filesystem functions. To work with a filesystem you shoul

You can start with GMock from https://goo.gl/j7EkQX, good luck!
*/

/*
* Test plan:
* 1. Copy single file
* 2. Copy several files
* 3. Copy folder with files
* 4. Copy folder with folders and files
*/

#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "FakeFileSystem.h"

class IFileCopier
{
public:
virtual void CopyFolderRecursive(const path& src, const path& dst) = 0;
};


TEST(FakeFileSystem, RootTest)
{
FakeFileSystem fs;
EXPECT_TRUE(fs.DirExists(root));
EXPECT_TRUE(fs.GetChildren(root).empty());
}

TEST(FakeFileSystem, SingleFileTest)
{
File file("file");
FileSystemObjects rootObjects = { file };
FakeFileSystem fs(rootObjects);

EXPECT_TRUE(fs.DirExists(root));
EXPECT_TRUE(fs.FileExists(root / "file"));
ASSERT_EQ(1, fs.GetChildren(root).size());
EXPECT_EQ("file", *fs.GetChildren(root).begin());
}

TEST(FakeFileSystem, SingleFolderTest)
{
Folder folder("folder");
FileSystemObjects rootObjects = { folder };
FakeFileSystem fs(rootObjects);

EXPECT_TRUE(fs.DirExists(root));
EXPECT_TRUE(fs.DirExists(root / "folder"));
ASSERT_EQ(1, fs.GetChildren(root).size());
EXPECT_EQ("folder", *fs.GetChildren(root).begin());
}

TEST(FakeFileSystem, FoldersWithNextedFolders)
{
Folder folder1("folder1");
Folder folder2("folder2", FileSystemObjects { folder1 });
Folder folder3("folder3", FileSystemObjects { folder2 });
FileSystemObjects rootObjects = { folder3 };
FakeFileSystem fs(rootObjects);

EXPECT_TRUE(fs.DirExists(root));
ASSERT_EQ(1, fs.GetChildren(root).size());
EXPECT_TRUE(fs.DirExists(root / "folder3"));
ASSERT_EQ(1, fs.GetChildren(root / "folder3").size());
EXPECT_TRUE(fs.DirExists(root / "folder3" / "folder2"));
ASSERT_EQ(1, fs.GetChildren(root / "folder3" / "folder2").size());
EXPECT_TRUE(fs.DirExists(root / "folder3" / "folder2" / "folder1"));
ASSERT_EQ(0, fs.GetChildren(root / "folder3" / "folder2" / "folder1").size());
}

TEST(FakeFileSystem, FoldersWithNestedFoldersAndFiles)
{
File file2("nested_file");
Folder folder2("nested_folder", FileSystemObjects { file2 } );
File file1("root_file");
Folder folder1("root_folder", FileSystemObjects { folder2 });

FileSystemObjects rootObjects = { file1, folder1 };
FakeFileSystem fs(rootObjects);

EXPECT_TRUE(fs.DirExists(root));
ASSERT_EQ(2, fs.GetChildren(root).size());
EXPECT_TRUE(fs.DirExists(root / "root_folder"));
EXPECT_TRUE(fs.FileExists(root / "root_file"));
ASSERT_EQ(1, fs.GetChildren(root / "root_folder").size());
EXPECT_TRUE(fs.DirExists(root / "nested_folder"));
EXPECT_TRUE(fs.FileExists(root / "nested_folder" / "nested_file"));
}
12 changes: 6 additions & 6 deletions tdd_intro/homework/homework.pro
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
TEMPLATE = subdirs

SUBDIRS += \
01_bob \
02_leap_year \
03_anagram \
04_trinary_numbers \
05_word_wrapp \
06_bank_ocr \
#01_bob \
#02_leap_year \
#03_anagram \
#04_trinary_numbers \
#05_word_wrapp \
#06_bank_ocr \
07_filecopier \
08_timer
Loading