testing
This commit is contained in:
parent
143f745b02
commit
dc9f4a6a4e
10 changed files with 202 additions and 64 deletions
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ private:
|
|||
|
||||
private:
|
||||
std::map<std::string, Command> mCommands;
|
||||
FileSystem mFileSystem;
|
||||
std::string mError;
|
||||
|
||||
public:
|
||||
FileSystem mFileSystem;
|
||||
bool verbose = true;
|
||||
};
|
||||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
21
src/Link.cpp
21
src/Link.cpp
|
|
@ -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());
|
||||
|
|
|
|||
10
src/Node.cpp
10
src/Node.cpp
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
|||
118
test/Tests.cpp
118
test/Tests.cpp
|
|
@ -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
47
test/Tests.hpp
Normal 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());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue