This commit is contained in:
IlyaShurupov 2024-03-30 22:28:47 +03:00
parent 143f745b02
commit dc9f4a6a4e
10 changed files with 202 additions and 64 deletions

View file

@ -28,6 +28,7 @@ public:
bool makeLink(const Path& source, const Path& to, bool isDynamic);
void log() const;
ui64 size() const;
static const std::string& getLastError();

View file

@ -21,6 +21,9 @@ private:
private:
std::map<std::string, Command> mCommands;
FileSystem mFileSystem;
std::string mError;
public:
FileSystem mFileSystem;
bool verbose = true;
};

View file

@ -37,7 +37,7 @@ public:
virtual std::shared_ptr<Node> findNode(const std::vector<Key>& path, ui32 currentDepth = 0);
virtual std::shared_ptr<Node> findNode(const Key& path) { return nullptr; }
virtual void clearFlags(std::shared_ptr<Node>& directory) {}
virtual void clearFlags(std::shared_ptr<Node>& directory);
virtual bool isHardNode() const;
virtual void removeIncomingDynamicLinks();
virtual void removeOutgoingLinks() {}

View file

@ -55,11 +55,11 @@ void Directory::getMaxDepthUtil(ui32 depth, ui32& maxDepth) const {
void Directory::dumpUtil(std::stringstream& ss, const Key& key, ui32 currentDepth, std::vector<bool>& indents) {
indents[currentDepth] = true;
indent(ss, currentDepth, indents);
ss << key;
// ss << " [" << mIncomingHardLinks.size() << ":" << mIncomingDynamicLinks.size() << "] " << size();
ss << " [" << mWorkingNodeFlag.lock().get() << "] ";
ss << " [h" << mIncomingHardLinks.size() << ": d" << mIncomingDynamicLinks.size() << "] ";
// ss << " [" << mWorkingNodeFlag.lock().get() << "] ";
ss << "\n";
currentDepth++;
@ -90,14 +90,6 @@ std::shared_ptr<Node> Directory::clone() const {
member.second->mParent = out;
}
for (auto& member : out->mMembers) {
std::shared_ptr<Node>& node = member.second;
if (auto linkNode = std::dynamic_pointer_cast<Link>(node)) {
auto targetNode = linkNode->getTarget();
assert(Link::linkNodes(linkNode, targetNode, linkNode->isHardLink()));
}
}
return out;
}

View file

@ -81,6 +81,11 @@ bool FileSystem::makeDirectory(const Path& path) {
return true;
}
if (parentNode->getType() != Node::DIRECTORY) {
gError = "Target path is not a directory";
return false;
}
auto directory = std::make_shared<Directory>();
directory->mParent = parentNode;
@ -110,6 +115,11 @@ bool FileSystem::makeFile(const Path& path) {
return true;
}
if (parentNode->getType() != Node::DIRECTORY) {
gError = "Target path is not a directory";
return false;
}
auto newFile = std::make_shared<Node>();
newFile->mParent = parentNode;
@ -146,6 +156,11 @@ bool FileSystem::makeLink(const Path& source, const Path& target, bool isDynamic
return false;
}
if (parentNodeTarget->getType() != Node::DIRECTORY) {
gError = "Target path is not a directory";
return false;
}
const Key& key = source.getFilename();
if (parentNodeTarget->findNode(key)) {
@ -161,7 +176,11 @@ bool FileSystem::makeLink(const Path& source, const Path& target, bool isDynamic
return false;
}
assert(parentNodeTarget->attachNode(key, newLink));
if (!parentNodeTarget->attachNode(key, newLink)) {
log();
}
// assert(parentNodeTarget->attachNode(key, newLink));
return true;
}
@ -247,6 +266,7 @@ bool FileSystem::removeFileOrLink(const Path &path) {
return false;
}
existingNode->removeIncomingDynamicLinks();
existingNode->removeOutgoingLinks();
if (!parentNode->detachNode(path.getFilename())) {
@ -347,6 +367,11 @@ bool FileSystem::moveNode(const Path &source, const Path &target) {
return false;
}
if (parentNodeTarget->getType() != Node::DIRECTORY) {
gError = "Target path is not a directory";
return false;
}
assert(parentNodeTarget->attachNode(key, sourceNode));
assert(parentNodeSource->detachNode(key));
@ -395,4 +420,8 @@ bool FileSystem::isPathContains(const std::shared_ptr<Node>& node, const std::sh
}
return true;
}
ui64 FileSystem::size() const {
return root->size();
}

View file

@ -109,10 +109,8 @@ bool Interpreter::interpret(const std::string& command) {
std::vector<std::string> words;
getWords(command, words);
std::cout << command << "\n";
if (words.empty()) {
reportError("Empty command");
if (verbose && 0) reportError("Empty command");
return false;
}
@ -122,24 +120,25 @@ bool Interpreter::interpret(const std::string& command) {
auto iter = mCommands.find(commandName);
if (iter == mCommands.end()) {
reportError("Command not found");
printHelp();
if (verbose && 0) reportError("Command not found");
if (verbose && 0) printHelp();
return false;
}
if (iter->second.numArguments != words.size() - 1) {
reportError("Invalid number of arguments given for: " + commandName);
if (verbose && 0) reportError("Invalid number of arguments given for: " + commandName);
return false;
}
bool success = iter->second.callback(mFileSystem, words);
mFileSystem.log();
if (verbose && success) std::cout << command << "\n";
if (verbose && success) mFileSystem.log();
if (!success) {
reportError(FileSystem::getLastError());
if (verbose && 0) reportError(FileSystem::getLastError());
return false;
}
return true;
}
}

View file

@ -4,16 +4,18 @@
#include <sstream>
#include <cassert>
#include <algorithm>
#include <iostream>
Link::Link() {}
Link::Link(const Link &node) : Node(node) {
mLink = node.mLink;
mIsHard = node.mIsHard;
}
std::shared_ptr<Node> Link::clone() const {
return std::make_shared<Link>(*this);
auto out = std::make_shared<Link>(*this);
Link::linkNodes(out, getLink(), isHardLink());
return out;
}
Link::~Link() = default;
@ -42,7 +44,9 @@ void Link::removeOutgoingLinks() {
auto& links = isHardLink() ? target->mIncomingHardLinks : target->mIncomingDynamicLinks;
links.erase(std::remove_if(links.begin(), links.end(), [&](std::weak_ptr<Link>& node){
auto targetLink = node.lock();
return !targetLink || targetLink.get() == this;
assert(targetLink);
auto res = targetLink.get() == this;
return res;
}), links.end());
}
@ -62,12 +66,17 @@ std::shared_ptr<Node> Link::getTarget() {
std::shared_ptr<Node> Link::findNode(const std::vector<Key>& path, ui32 currentDepth) {
assert(path.size() != currentDepth);
return getLink()->findNode(path, currentDepth + 1);
return getLink()->findNode(path, currentDepth);
}
void Link::dumpUtil(std::stringstream& ss, const Key& key, ui32 currentDepth, std::vector<bool>& indents) {
indent(ss, currentDepth, indents);
ss << key << (isHardLink() ? " hlink[" : " dlink[");
ss << key;
ss << (isHardLink() ? " hlink[" : " dlink[");
ss << " [h" << mIncomingHardLinks.size() << ": d" << mIncomingDynamicLinks.size() << "] ";
std::vector<std::shared_ptr<Node>> path;
getNodeStraightPath(getLink(), path);
std::reverse(path.begin(), path.end());

View file

@ -31,10 +31,14 @@ ui32 Node::getMaxDepth() const {
}
std::shared_ptr<Node> Node::findNode(const std::vector<Key>& path, ui32 currentDepth) {
assert(false);
// assert(false);
return nullptr;
}
void Node::clearFlags(std::shared_ptr<Node>& directory) {
mWorkingNodeFlag = directory;
}
bool Node::isHardNode() const {
return std::any_of(mIncomingHardLinks.begin(), mIncomingHardLinks.end(), [this](const std::weak_ptr<Link>& hardLink) {
auto linkNode = hardLink.lock();
@ -56,7 +60,7 @@ void Node::removeIncomingDynamicLinks() {
auto linkTarget = linkNode->mWorkingNodeFlag.lock();
if (linkTarget && ownLink == linkTarget) {
continue;
// continue;
}
auto parentNode = linkNode->mParent.lock();
@ -85,7 +89,7 @@ void Node::dump(std::stringstream& ss) {
void Node::dumpUtil(std::stringstream& ss, const Key& key, ui32 currentDepth, std::vector<bool>& indents) {
indent(ss, currentDepth, indents);
ss << key;
// ss << " [file]";
ss << " [h" << mIncomingHardLinks.size() << ": d" << mIncomingDynamicLinks.size() << "] ";
ss << "\n";
}

View file

@ -1,37 +1,91 @@
#include "Interpreter.hpp"
#include "UnitTest++/UnitTest++.h"
#include <iostream>
#include "Tests.hpp"
SUITE(FSE) {
TEST (Simple) {
Interpreter interpreter;
auto interp = [&](auto name) {
interpreter.interpret(name);
};
interp("md a");
interp("md a/b");
interp("mdl a a/b");
interp("copy a C:/");
interp("deltree a");
interp("deltree a_copy");
interp("md a");
interp("md a/b");
interp("mhl a a/b");
interp("copy a C:/");
interp("deltree a");
interp("deltree a_copy");
interp("del a/b/a");
interp("deltree a");
interp("md a");
interp("md a/b");
interp("mdl a a/b");
interp("copy a C:/");
interp("md c");
interp("move a c");
interp("move a_copy c");
interp("copy c C:/");
interp("deltree c");
}
TEST (CommandNoise) {
Interpreter interpreter;
StringDistribution commands({
{ "md", 10 },
{ "mf", 10 },
{ "mhl", 10 },
{ "mdl", 10 },
{ "cd", 5 },
{ "rd", 1 },
{ "del", 10 },
{ "deltree", 10 },
{ "move", 20 },
{ "copy", 20 },
});
StringDistribution names({
{ "C:", 1 },
{ "a", 1 },
{ "b", 1 },
{ "c", 1 },
{ "d", 1 },
{ "e", 1 },
});
std::discrete_distribution<int> pathLenDist({ 0.1, 0.2, 0.4, 0.5, 0.1 });
auto generatePath = [&](std::stringstream& ss) {
ss << " ";
auto len = pathLenDist(rng);
if (len) ss << names.get();
for (auto i = 1; i < len; i++) {
ss <<"/" << names.get();
}
};
runFor(interpreter, timeLimitSec, itemLimit, [&]() {
std::stringstream ss;
ss << commands.get();
generatePath(ss);
if (pathLenDist(rng) % 2) generatePath(ss);
return ss.str();
});
interpreter.mFileSystem.log();
}
}
int main() {
Interpreter interpreter;
interpreter.interpret("md a");
interpreter.interpret("md a/b");
interpreter.interpret("mdl a a/b");
interpreter.interpret("copy a C:/");
interpreter.interpret("deltree a");
interpreter.interpret("deltree a_copy");
interpreter.interpret("md a");
interpreter.interpret("md a/b");
interpreter.interpret("mhl a a/b");
interpreter.interpret("copy a C:/");
interpreter.interpret("deltree a");
interpreter.interpret("deltree a_copy");
interpreter.interpret("del a/b/a");
interpreter.interpret("deltree a");
interpreter.interpret("md a");
interpreter.interpret("md a/b");
interpreter.interpret("mdl a a/b");
interpreter.interpret("copy a C:/");
interpreter.interpret("md c");
interpreter.interpret("move a c");
interpreter.interpret("move a_copy c");
interpreter.interpret("copy c C:/");
interpreter.interpret("deltree c");
return UnitTest::RunAllTests();
}

47
test/Tests.hpp Normal file
View file

@ -0,0 +1,47 @@
#pragma once
#include "Interpreter.hpp"
#include "UnitTest++/UnitTest++.h"
#include <random>
#include <chrono>
const ui64 timeLimitSec = 5;
const ui64 itemLimit = 1e6;
std::random_device rd;
std::mt19937 rng;
class StringDistribution {
private:
std::vector<std::string> commandList;
std::vector<double> probabilities;
std::discrete_distribution<int> distribution;
public:
explicit StringDistribution(const std::map<std::string, double>& commands) {
for (const auto& command : commands) {
commandList.push_back(command.first);
probabilities.push_back(command.second);
}
double sum = std::accumulate(probabilities.begin(), probabilities.end(), 0.0);
std::for_each(probabilities.begin(), probabilities.end(), [sum](double& element) { element /= sum; });
distribution = std::discrete_distribution<int>(probabilities.begin(), probabilities.end());
}
std::string get() {
return commandList[distribution(rng)];
}
};
template<typename tDriver>
void runFor(Interpreter& interpreter, ui64 time, ui64 size, tDriver driver) {
auto startTime = std::chrono::steady_clock::now();
while (true) {
auto currentTime = std::chrono::steady_clock::now();
double elapsedSeconds = std::chrono::duration<double>(currentTime - startTime).count();
if (elapsedSeconds >= (double) time || interpreter.mFileSystem.size() > size) break;
interpreter.interpret(driver());
}
}