Added FileTape constuctor that initializes FileTape from vector of uint32_t
Slight rewrite of fill_file_with_empty_cells Adjusted seek offset in some FileTape operations Unit tests now work with vector of uint32_t as source of test data
This commit is contained in:
parent
680ec28b57
commit
4397e519bf
4 changed files with 89 additions and 51 deletions
|
@ -4,6 +4,7 @@
|
|||
#include "tape.h"
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
using std::chrono::milliseconds;
|
||||
|
||||
|
@ -55,7 +56,7 @@ class FileTape : public Tape {
|
|||
std::string file_name;
|
||||
std::fstream file;
|
||||
FileTapeSettings settings;
|
||||
bool temp = false;
|
||||
bool tmp = false;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
@ -81,24 +82,45 @@ class FileTape : public Tape {
|
|||
|
||||
/**
|
||||
* Initializes a new instance of FileTape that will create and open a file
|
||||
* with the specified name, and write *size* zeroes into it.
|
||||
* with the specified name and fill it with *cells* amount of zeroed cells.
|
||||
* File must not exist and directory must be write accessible.
|
||||
*
|
||||
* Writing operations when filling file with zeroes will not introduce any
|
||||
* delay.
|
||||
*
|
||||
* @param size Size of a newly created FileTpae
|
||||
* @param file_name Name of a file to be created and opened
|
||||
* @param settings FileTape settings
|
||||
*/
|
||||
FileTape(size_t size, std::string file_name,
|
||||
FileTape(size_t cells, std::string file_name,
|
||||
FileTapeSettings settings = FT_DEFAULT_SETTINGS);
|
||||
|
||||
/**
|
||||
* Initializes a new instance of FileTape that will create and open a
|
||||
* temporary file, and write *size* zeroes into it.
|
||||
* temporary file and fill it with *cells* amount of zeroed cells.
|
||||
*
|
||||
* Writing operations when filling file with zeroes will not introduce any
|
||||
* delay.
|
||||
*
|
||||
* @param size Size of a newly created FileTape
|
||||
* @param settings FileTape settings
|
||||
*/
|
||||
FileTape(size_t size, FileTapeSettings settings = FT_DEFAULT_SETTINGS);
|
||||
FileTape(size_t cells, FileTapeSettings settings = FT_DEFAULT_SETTINGS);
|
||||
|
||||
/**
|
||||
* Initializes a new instance of FileTape that will create and open a
|
||||
* temporary file, and fill it with the data from the provided vector.
|
||||
*
|
||||
* Writing operations when copying vector to a FileTape will not have any
|
||||
* delay.
|
||||
* Use this constructor ONLY FOR TESTING. Do NOT use it to copy one
|
||||
* FileTape's data to another.
|
||||
*
|
||||
* @param data Vector of uint32 contents of which will be copied to FileTape
|
||||
* @param settings FileTape settings
|
||||
*/
|
||||
FileTape(const std::vector<uint32_t> &data,
|
||||
FileTapeSettings settings = FT_DEFAULT_SETTINGS);
|
||||
|
||||
/**
|
||||
* Advances the underlying fstream to a new line.
|
||||
|
@ -128,11 +150,15 @@ class FileTape : public Tape {
|
|||
*/
|
||||
void write(uint32_t data) override;
|
||||
|
||||
/**
|
||||
* Close the undetlying fstream, and, in case the FileTape is marked as
|
||||
* temporary (tmp is set to true), remove the temporary file
|
||||
*/
|
||||
~FileTape() override;
|
||||
|
||||
// Define getters in header file since they are implicitly inlined
|
||||
|
||||
bool is_temp() const { return this->temp; }
|
||||
bool is_tmp() const { return this->tmp; }
|
||||
|
||||
const FileTapeSettings &get_settings() const { return this->settings; }
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#include "filetape.h"
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
using std::fstream;
|
||||
|
@ -14,11 +17,11 @@ std::string generate_tmp_file_name() {
|
|||
return tmp_file_name.data();
|
||||
}
|
||||
|
||||
void fill_file_with_empty_cells(size_t size, fstream &file) {
|
||||
file << std::setfill('0') << std::setw(tape::FT_CELL_SIZE + 1);
|
||||
for (int i = 0; i < size; i++) {
|
||||
void fill_file_with_empty_cells(size_t cells, fstream &file) {
|
||||
file << std::setfill('0') << std::setw(tape::FT_CELL_SIZE) << '0';
|
||||
for (size_t i = 1; i < cells; i++) {
|
||||
file << tape::FT_DELIMETER << std::setfill('0')
|
||||
<< std::setw(tape::FT_CELL_SIZE + 1);
|
||||
<< std::setw(tape::FT_CELL_SIZE) << '0';
|
||||
}
|
||||
file.seekg(0, fstream::beg);
|
||||
}
|
||||
|
@ -28,20 +31,37 @@ FileTape::FileTape(std::string file_name, FileTapeSettings settings)
|
|||
this->file = fstream(file_name);
|
||||
}
|
||||
|
||||
FileTape::FileTape(size_t size, std::string file_name,
|
||||
FileTape::FileTape(size_t cells, std::string file_name,
|
||||
FileTapeSettings settings)
|
||||
: FileTape(file_name, settings) {
|
||||
this->file =
|
||||
fstream(this->file_name, fstream::in | fstream::out | fstream::trunc);
|
||||
fill_file_with_empty_cells(size, this->file);
|
||||
fill_file_with_empty_cells(cells, this->file);
|
||||
}
|
||||
|
||||
FileTape::FileTape(size_t size, FileTapeSettings settings)
|
||||
: settings(settings), temp(true) {
|
||||
FileTape::FileTape(size_t cells, FileTapeSettings settings)
|
||||
: settings(settings), tmp(true) {
|
||||
this->file_name = generate_tmp_file_name();
|
||||
this->file =
|
||||
fstream(this->file_name, fstream::in | fstream::out | fstream::trunc);
|
||||
fill_file_with_empty_cells(size, this->file);
|
||||
fill_file_with_empty_cells(cells, this->file);
|
||||
}
|
||||
|
||||
FileTape::FileTape(const std::vector<uint32_t> &data, FileTapeSettings settings)
|
||||
: settings(settings), tmp(true) {
|
||||
this->file_name = generate_tmp_file_name();
|
||||
this->file =
|
||||
fstream(this->file_name, fstream::in | fstream::out | fstream::trunc);
|
||||
if (data.empty()) {
|
||||
return;
|
||||
}
|
||||
this->file << std::setfill('0') << std::setw(FT_CELL_SIZE)
|
||||
<< std::to_string(data[0]);
|
||||
for (size_t i = 1; i < data.size(); i++) {
|
||||
this->file << FT_DELIMETER << std::setfill('0')
|
||||
<< std::setw(FT_CELL_SIZE) << std::to_string(data[i]);
|
||||
}
|
||||
this->file.seekg(0, fstream::beg);
|
||||
}
|
||||
|
||||
bool FileTape::seek_backwards() {
|
||||
|
@ -56,10 +76,10 @@ bool FileTape::seek_backwards() {
|
|||
bool FileTape::seek_forward() {
|
||||
std::this_thread::sleep_for(this->settings.seek_forward_delay);
|
||||
this->file.seekg(FT_SEEK_OFFSET, fstream::cur);
|
||||
this->file.peek();
|
||||
this->file.peek(); // peek to check if eof is reached
|
||||
if (this->file.eof()) {
|
||||
this->file.clear();
|
||||
this->file.seekg(-FT_SEEK_OFFSET, fstream::end);
|
||||
this->file.clear(); // reset fstream
|
||||
this->file.seekg(-FT_SEEK_OFFSET + 1, fstream::end);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -70,8 +90,8 @@ uint32_t FileTape::read() {
|
|||
uint32_t data = 0;
|
||||
this->file >> data;
|
||||
if (this->file.eof()) {
|
||||
this->file.clear();
|
||||
this->file.seekg(-FT_SEEK_OFFSET + 2, fstream::end);
|
||||
this->file.clear(); // reset fstream
|
||||
this->file.seekg(-FT_SEEK_OFFSET + 1, fstream::end);
|
||||
return data;
|
||||
}
|
||||
this->file.seekg(-FT_SEEK_OFFSET + 1, fstream::cur);
|
||||
|
@ -89,7 +109,7 @@ void FileTape::write(uint32_t data) {
|
|||
|
||||
FileTape::~FileTape() {
|
||||
this->file.close();
|
||||
if (this->is_temp()) {
|
||||
if (this->is_tmp()) {
|
||||
std::filesystem::remove(this->file_name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,4 +5,3 @@ target_link_libraries(filetape_tests PRIVATE tapelib)
|
|||
target_link_libraries(filetape_tests PRIVATE Catch2::Catch2WithMain)
|
||||
|
||||
add_test(filetape_tests filetape_tests)
|
||||
add_compile_definitions(FILETAPE_TEST_FILE=\"${PROJECT_SOURCE_DIR}/tests/assets/filetape_test_data.txt\")
|
||||
|
|
|
@ -1,61 +1,54 @@
|
|||
#include "filetape.h"
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
const static std::string TEST_DATA = "0000000001\n"
|
||||
"0000012345\n"
|
||||
"0000000000\n"
|
||||
"2222222222\n"
|
||||
"4294967295";
|
||||
|
||||
tape::FileTape prepare_test_filetape() {
|
||||
tape::FileTape tape(0);
|
||||
|
||||
return tape;
|
||||
}
|
||||
const static std::vector<uint32_t> TEST_DATA = {1, 12345, 0, 2222222222,
|
||||
4294967295};
|
||||
|
||||
// NOLINTBEGIN(readability-function-cognitive-complexity)
|
||||
TEST_CASE("Reading data from a FileTape", "[filetape]") {
|
||||
tape::FileTape tape(FILETAPE_TEST_FILE);
|
||||
tape::FileTape tape(TEST_DATA);
|
||||
|
||||
SECTION("Read all data sequentially") {
|
||||
REQUIRE(tape.read() == 1);
|
||||
REQUIRE(tape.read() == TEST_DATA[0]);
|
||||
REQUIRE(tape.seek_forward() == true);
|
||||
REQUIRE(tape.read() == 2);
|
||||
REQUIRE(tape.read() == TEST_DATA[1]);
|
||||
REQUIRE(tape.seek_forward() == true);
|
||||
REQUIRE(tape.read() == 3);
|
||||
REQUIRE(tape.read() == TEST_DATA[2]);
|
||||
REQUIRE(tape.seek_forward() == true);
|
||||
REQUIRE(tape.read() == 4);
|
||||
REQUIRE(tape.read() == TEST_DATA[3]);
|
||||
REQUIRE(tape.seek_forward() == true);
|
||||
REQUIRE(tape.read() == 5);
|
||||
REQUIRE(tape.read() == TEST_DATA[4]);
|
||||
}
|
||||
|
||||
SECTION("Read data non-sequentially") {
|
||||
REQUIRE(tape.read() == 1);
|
||||
REQUIRE(tape.read() == TEST_DATA[0]);
|
||||
REQUIRE(tape.seek_forward() == true);
|
||||
REQUIRE(tape.read() == 2);
|
||||
REQUIRE(tape.read() == TEST_DATA[1]);
|
||||
REQUIRE(tape.seek_backwards() == true);
|
||||
REQUIRE(tape.read() == 1);
|
||||
REQUIRE(tape.read() == TEST_DATA[0]);
|
||||
REQUIRE(tape.seek_forward() == true);
|
||||
REQUIRE(tape.seek_forward() == true);
|
||||
REQUIRE(tape.seek_forward() == true);
|
||||
REQUIRE(tape.read() == 4);
|
||||
REQUIRE(tape.read() == TEST_DATA[3]);
|
||||
REQUIRE(tape.seek_backwards() == true);
|
||||
REQUIRE(tape.seek_backwards() == true);
|
||||
REQUIRE(tape.read() == 2);
|
||||
REQUIRE(tape.read() == TEST_DATA[1]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Seeking forward and backwards", "[filetape]") {
|
||||
tape::FileTape tape(FILETAPE_TEST_FILE);
|
||||
tape::FileTape tape(TEST_DATA);
|
||||
|
||||
SECTION("Rewinding at the beginning of a file tape") {
|
||||
REQUIRE(tape.seek_backwards() == false);
|
||||
REQUIRE(tape.read() == 1);
|
||||
REQUIRE(tape.read() == TEST_DATA[0]);
|
||||
REQUIRE(tape.seek_forward() == true);
|
||||
REQUIRE(tape.read() == 2);
|
||||
REQUIRE(tape.read() == TEST_DATA[1]);
|
||||
REQUIRE(tape.seek_backwards() == true);
|
||||
REQUIRE(tape.seek_backwards() == false);
|
||||
REQUIRE(tape.read() == 1);
|
||||
REQUIRE(tape.read() == TEST_DATA[0]);
|
||||
}
|
||||
|
||||
SECTION("Seeking at the end of a file tape") {
|
||||
|
@ -65,12 +58,12 @@ TEST_CASE("Seeking forward and backwards", "[filetape]") {
|
|||
REQUIRE(tape.seek_forward() == true);
|
||||
}
|
||||
REQUIRE(tape.seek_forward() == false);
|
||||
REQUIRE(tape.read() == 5);
|
||||
REQUIRE(tape.read() == TEST_DATA[4]);
|
||||
REQUIRE(tape.seek_backwards() == true);
|
||||
REQUIRE(tape.read() == 4);
|
||||
REQUIRE(tape.read() == TEST_DATA[3]);
|
||||
REQUIRE(tape.seek_forward() == true);
|
||||
REQUIRE(tape.seek_forward() == false);
|
||||
REQUIRE(tape.read() == 5);
|
||||
REQUIRE(tape.read() == TEST_DATA[4]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue