Added delimeter and settings constants to FileTape

Removed unneccesary copy and move constructors
Added constructor for tmp FileTape
Added Catch2 for unit testing
Added example unit tests
This commit is contained in:
Egor 2024-10-24 17:48:55 +03:00
parent cab1b88a77
commit 0e49b35f12
6 changed files with 157 additions and 25 deletions

View file

@ -2,6 +2,7 @@
#define FILE_TAPE_H #define FILE_TAPE_H
#include "tape.h" #include "tape.h"
#include <cstddef>
#include <cstdint> #include <cstdint>
#include <fstream> #include <fstream>
#include <string> #include <string>
@ -19,39 +20,68 @@ struct FileTapeSettings {
unsigned int seek_backwards_delay_ms; unsigned int seek_backwards_delay_ms;
}; };
const static struct FileTapeSettings DEFAULT_FT_SETTINGS =
FileTapeSettings{.read_delay_ms = 0,
.write_delay_ms = 0,
.seek_forward_delay_ms = 0,
.seek_backwards_delay_ms = 0};
const static char FT_DELIMETER = '\n';
/** /**
* Mock tape implementation that uses text files as data source. * Mock tape implementation that uses text files as data source.
* *
* Simulates tape operations by artificially pausing the execution of some * Simulates tape operations by artificially pausing the execution of some
* methods using time intervals, specified in command line arguments or a * methods using time intervals, specified in command line arguments or a
* configuration file. Each cell is represented as a seperate line in a file, * configuration file. Each cell is represented as a plain text 32-bit int
* cell data is stored as plain text. * separated by FT_DELIMETER. End of the file tape is indicated either by EOF
* or some arbitrary data that cannot be parsed to int32_t
*/ */
class FileTape : public Tape { class FileTape : public Tape {
private: private:
std::fstream file; std::fstream file;
FileTapeSettings settings; FileTapeSettings settings;
size_t prev_line_pos = 0;
bool at_first_line = false;
public: public:
FileTape &operator=(const FileTape &) = delete;
FileTape(const FileTape &) = delete;
FileTape(FileTape &&) = delete;
FileTape &operator=(FileTape &&) = delete;
~FileTape() override;
/** /**
* Initialize a new instance of FileTape that will open a file with the * Initializes a new instance of FileTape that will open an existing file
* specified name. File must be read and write accessible. * with the specified name, already filled with data. File must be read and
* write accessible.
* *
* @param file_name Name of a file to be opened. * @param file_name Name of a file to be opened.
* @param settings File tape settings * @param settings FileTape settings
*/ */
explicit FileTape(const std::string &file_name, FileTapeSettings settings); explicit FileTape(const std::string &file_name,
FileTapeSettings settings = DEFAULT_FT_SETTINGS);
/**
* Initializes a new instance of FileTape that will create and open a file
* with the specified name, and write *size* zeroes into it.
* File must not exist and directory must be write accessible.
*
* @param size Size of a newly created FileTpae
* @param file_name Name of a file to be created and opened
* @param settings FileTape settings
*/
explicit FileTape(size_t size, const std::string &file_name,
FileTapeSettings settings = DEFAULT_FT_SETTINGS);
/**
* Initializes a new instance of FileTape that will create and open a
* temporary file, and write *size* zeroes into it.
*
* @param size Size of a newly created FileTape
* @param settings FileTape settings
*/
explicit FileTape(size_t size,
FileTapeSettings settings = DEFAULT_FT_SETTINGS);
/** /**
* Advances the underlying fstream to a new line. * Advances the underlying fstream to a new line.
* *
* @return false if EOF is reached, otherwise true. * @return false if empty line is reached, otherwise true.
*/ */
bool seek_forward() override; bool seek_forward() override;

View file

@ -17,11 +17,11 @@ namespace tape {
*/ */
class Tape { class Tape {
public: public:
Tape(const Tape &) = default;
Tape(Tape &&) = default;
Tape &operator=(const Tape &) = default;
Tape &operator=(Tape &&) = default;
Tape() = default; Tape() = default;
Tape(const Tape &) = default;
Tape(Tape &&) = delete;
Tape &operator=(const Tape &) = default;
Tape &operator=(Tape &&) = delete;
virtual ~Tape() = default; virtual ~Tape() = default;
/** /**

View file

@ -1,20 +1,41 @@
#include "filetape.h" #include "filetape.h"
#include <array>
#include <cstdint> #include <cstdint>
#include <cstdio>
#include <fstream> #include <fstream>
#include <string> #include <string>
tape::FileTape::FileTape(const std::string &file_name, using tape::FileTape;
FileTapeSettings settings)
FileTape::FileTape(const std::string &file_name, FileTapeSettings settings)
: settings(settings) { : settings(settings) {
this->file = std::fstream(file_name); this->file = std::fstream(file_name);
} }
bool tape::FileTape::seek_forward() { return true; } FileTape::FileTape(size_t size, const std::string &file_name,
FileTapeSettings settings)
: FileTape(file_name, settings) {
this->file << "0";
for (int i = 0; i < size; i++) {
this->file << FT_DELIMETER << "0";
}
}
bool tape::FileTape::seek_backwards() { return true; } FileTape::FileTape(size_t size, FileTapeSettings settings)
: settings(settings) {
std::array<char, L_tmpnam> file_name{};
std::tmpnam(file_name.data());
this->file = std::fstream(file_name.data());
this->file << "0";
for (int i = 0; i < size; i++) {
this->file << FT_DELIMETER << "0";
}
}
int32_t tape::FileTape::read() { return 0; } bool FileTape::seek_forward() { return true; }
void tape::FileTape::write(int32_t data) {} bool FileTape::seek_backwards() { return true; }
tape::FileTape::~FileTape() { this->file.close(); } int32_t FileTape::read() { return 0; }
void FileTape::write(int32_t data) {}

View file

@ -1,4 +1,7 @@
find_package(Catch2 3 REQUIRED)
add_executable(filetape_tests ${PROJECT_SOURCE_DIR}/tests/filetape_tests.cpp) add_executable(filetape_tests ${PROJECT_SOURCE_DIR}/tests/filetape_tests.cpp)
target_link_libraries(filetape_tests PRIVATE tapelib) target_link_libraries(filetape_tests PRIVATE tapelib)
target_link_libraries(filetape_tests PRIVATE Catch2::Catch2WithMain)
add_test(filetape_tests filetape_tests) add_test(filetape_tests filetape_tests)

View file

@ -0,0 +1,5 @@
1
2
3
4
5

View file

@ -1 +1,74 @@
int main(int argc, char *argv[]) { return 0; } #include "filetape.h"
#include <catch2/catch_test_macros.hpp>
#include <cstdio>
// NOLINTBEGIN(readability-function-cognitive-complexity)
TEST_CASE("Reading data from a FileTape", "[filetape]") {
tape::FileTape tape("assets/filetape_test_data.txt");
SECTION("Read all data sequentially") {
REQUIRE(tape.read() == 1);
REQUIRE(tape.seek_forward() == true);
REQUIRE(tape.read() == 2);
REQUIRE(tape.seek_forward() == true);
REQUIRE(tape.read() == 3);
REQUIRE(tape.seek_forward() == true);
REQUIRE(tape.read() == 4);
REQUIRE(tape.seek_forward() == true);
REQUIRE(tape.read() == 5);
}
SECTION("Read data non-sequentially") {
REQUIRE(tape.read() == 1);
REQUIRE(tape.seek_forward() == true);
REQUIRE(tape.read() == 2);
REQUIRE(tape.seek_backwards() == true);
REQUIRE(tape.read() == 1);
REQUIRE(tape.seek_forward() == true);
REQUIRE(tape.seek_forward() == true);
REQUIRE(tape.seek_forward() == true);
REQUIRE(tape.read() == 4);
REQUIRE(tape.seek_backwards() == true);
REQUIRE(tape.seek_backwards() == true);
REQUIRE(tape.read() == 2);
}
}
TEST_CASE("Seeking forward and backwards", "[filetape]") {
tape::FileTape tape("assets/filetape_test_data.txt");
SECTION("Rewinding at the beginning of a file tape") {
REQUIRE(tape.seek_backwards() == false);
REQUIRE(tape.read() == 1);
REQUIRE(tape.seek_forward() == true);
REQUIRE(tape.read() == 2);
REQUIRE(tape.seek_backwards() == true);
REQUIRE(tape.seek_backwards() == false);
REQUIRE(tape.read() == 1);
}
SECTION("Seeking at the end of a file tape") {
const int size = 5;
// seek to end of a file tape
for (int i = 0; i < size - 1; i++) {
REQUIRE(tape.seek_forward() == true);
}
REQUIRE(tape.seek_forward() == false);
REQUIRE(tape.read() == 5);
REQUIRE(tape.seek_backwards() == true);
REQUIRE(tape.read() == 4);
REQUIRE(tape.seek_forward() == true);
REQUIRE(tape.seek_forward() == false);
REQUIRE(tape.read() == 5);
}
}
TEST_CASE("Writing to a file tape", "[filetape]") {
// init a temp file to modify
// std::string tmp_file_name = "/tmp/"
// std::unique_ptr<std::FILE> tmp_file(std::tmpfile());
// std::fstream tmp(tmp_file);
// std::fstream tmp(tmp_file);
// tape::FileTape tape("assets/filetape_test_data.txt");
}
// NOLINTEND(readability-function-cognitive-complexity)