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 "tape.h"
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
using std::chrono::milliseconds;
|
using std::chrono::milliseconds;
|
||||||
|
|
||||||
|
@ -55,7 +56,7 @@ class FileTape : public Tape {
|
||||||
std::string file_name;
|
std::string file_name;
|
||||||
std::fstream file;
|
std::fstream file;
|
||||||
FileTapeSettings settings;
|
FileTapeSettings settings;
|
||||||
bool temp = false;
|
bool tmp = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -81,24 +82,45 @@ class FileTape : public Tape {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new instance of FileTape that will create and open a file
|
* 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.
|
* 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 size Size of a newly created FileTpae
|
||||||
* @param file_name Name of a file to be created and opened
|
* @param file_name Name of a file to be created and opened
|
||||||
* @param settings FileTape settings
|
* @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);
|
FileTapeSettings settings = FT_DEFAULT_SETTINGS);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new instance of FileTape that will create and open a
|
* 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 size Size of a newly created FileTape
|
||||||
* @param settings FileTape settings
|
* @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.
|
* Advances the underlying fstream to a new line.
|
||||||
|
@ -128,11 +150,15 @@ class FileTape : public Tape {
|
||||||
*/
|
*/
|
||||||
void write(uint32_t data) override;
|
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;
|
~FileTape() override;
|
||||||
|
|
||||||
// Define getters in header file since they are implicitly inlined
|
// 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; }
|
const FileTapeSettings &get_settings() const { return this->settings; }
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#include "filetape.h"
|
#include "filetape.h"
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
using std::fstream;
|
using std::fstream;
|
||||||
|
@ -14,11 +17,11 @@ std::string generate_tmp_file_name() {
|
||||||
return tmp_file_name.data();
|
return tmp_file_name.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill_file_with_empty_cells(size_t size, fstream &file) {
|
void fill_file_with_empty_cells(size_t cells, fstream &file) {
|
||||||
file << std::setfill('0') << std::setw(tape::FT_CELL_SIZE + 1);
|
file << std::setfill('0') << std::setw(tape::FT_CELL_SIZE) << '0';
|
||||||
for (int i = 0; i < size; i++) {
|
for (size_t i = 1; i < cells; i++) {
|
||||||
file << tape::FT_DELIMETER << std::setfill('0')
|
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);
|
file.seekg(0, fstream::beg);
|
||||||
}
|
}
|
||||||
|
@ -28,20 +31,37 @@ FileTape::FileTape(std::string file_name, FileTapeSettings settings)
|
||||||
this->file = fstream(file_name);
|
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)
|
FileTapeSettings settings)
|
||||||
: FileTape(file_name, settings) {
|
: FileTape(file_name, settings) {
|
||||||
this->file =
|
this->file =
|
||||||
fstream(this->file_name, fstream::in | fstream::out | fstream::trunc);
|
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)
|
FileTape::FileTape(size_t cells, FileTapeSettings settings)
|
||||||
: settings(settings), temp(true) {
|
: settings(settings), tmp(true) {
|
||||||
this->file_name = generate_tmp_file_name();
|
this->file_name = generate_tmp_file_name();
|
||||||
this->file =
|
this->file =
|
||||||
fstream(this->file_name, fstream::in | fstream::out | fstream::trunc);
|
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() {
|
bool FileTape::seek_backwards() {
|
||||||
|
@ -56,10 +76,10 @@ bool FileTape::seek_backwards() {
|
||||||
bool FileTape::seek_forward() {
|
bool FileTape::seek_forward() {
|
||||||
std::this_thread::sleep_for(this->settings.seek_forward_delay);
|
std::this_thread::sleep_for(this->settings.seek_forward_delay);
|
||||||
this->file.seekg(FT_SEEK_OFFSET, fstream::cur);
|
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()) {
|
if (this->file.eof()) {
|
||||||
this->file.clear();
|
this->file.clear(); // reset fstream
|
||||||
this->file.seekg(-FT_SEEK_OFFSET, fstream::end);
|
this->file.seekg(-FT_SEEK_OFFSET + 1, fstream::end);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -70,8 +90,8 @@ uint32_t FileTape::read() {
|
||||||
uint32_t data = 0;
|
uint32_t data = 0;
|
||||||
this->file >> data;
|
this->file >> data;
|
||||||
if (this->file.eof()) {
|
if (this->file.eof()) {
|
||||||
this->file.clear();
|
this->file.clear(); // reset fstream
|
||||||
this->file.seekg(-FT_SEEK_OFFSET + 2, fstream::end);
|
this->file.seekg(-FT_SEEK_OFFSET + 1, fstream::end);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
this->file.seekg(-FT_SEEK_OFFSET + 1, fstream::cur);
|
this->file.seekg(-FT_SEEK_OFFSET + 1, fstream::cur);
|
||||||
|
@ -89,7 +109,7 @@ void FileTape::write(uint32_t data) {
|
||||||
|
|
||||||
FileTape::~FileTape() {
|
FileTape::~FileTape() {
|
||||||
this->file.close();
|
this->file.close();
|
||||||
if (this->is_temp()) {
|
if (this->is_tmp()) {
|
||||||
std::filesystem::remove(this->file_name);
|
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)
|
target_link_libraries(filetape_tests PRIVATE Catch2::Catch2WithMain)
|
||||||
|
|
||||||
add_test(filetape_tests filetape_tests)
|
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 "filetape.h"
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
const static std::string TEST_DATA = "0000000001\n"
|
const static std::vector<uint32_t> TEST_DATA = {1, 12345, 0, 2222222222,
|
||||||
"0000012345\n"
|
4294967295};
|
||||||
"0000000000\n"
|
|
||||||
"2222222222\n"
|
|
||||||
"4294967295";
|
|
||||||
|
|
||||||
tape::FileTape prepare_test_filetape() {
|
|
||||||
tape::FileTape tape(0);
|
|
||||||
|
|
||||||
return tape;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOLINTBEGIN(readability-function-cognitive-complexity)
|
// NOLINTBEGIN(readability-function-cognitive-complexity)
|
||||||
TEST_CASE("Reading data from a FileTape", "[filetape]") {
|
TEST_CASE("Reading data from a FileTape", "[filetape]") {
|
||||||
tape::FileTape tape(FILETAPE_TEST_FILE);
|
tape::FileTape tape(TEST_DATA);
|
||||||
|
|
||||||
SECTION("Read all data sequentially") {
|
SECTION("Read all data sequentially") {
|
||||||
REQUIRE(tape.read() == 1);
|
REQUIRE(tape.read() == TEST_DATA[0]);
|
||||||
REQUIRE(tape.seek_forward() == true);
|
REQUIRE(tape.seek_forward() == true);
|
||||||
REQUIRE(tape.read() == 2);
|
REQUIRE(tape.read() == TEST_DATA[1]);
|
||||||
REQUIRE(tape.seek_forward() == true);
|
REQUIRE(tape.seek_forward() == true);
|
||||||
REQUIRE(tape.read() == 3);
|
REQUIRE(tape.read() == TEST_DATA[2]);
|
||||||
REQUIRE(tape.seek_forward() == true);
|
REQUIRE(tape.seek_forward() == true);
|
||||||
REQUIRE(tape.read() == 4);
|
REQUIRE(tape.read() == TEST_DATA[3]);
|
||||||
REQUIRE(tape.seek_forward() == true);
|
REQUIRE(tape.seek_forward() == true);
|
||||||
REQUIRE(tape.read() == 5);
|
REQUIRE(tape.read() == TEST_DATA[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Read data non-sequentially") {
|
SECTION("Read data non-sequentially") {
|
||||||
REQUIRE(tape.read() == 1);
|
REQUIRE(tape.read() == TEST_DATA[0]);
|
||||||
REQUIRE(tape.seek_forward() == true);
|
REQUIRE(tape.seek_forward() == true);
|
||||||
REQUIRE(tape.read() == 2);
|
REQUIRE(tape.read() == TEST_DATA[1]);
|
||||||
REQUIRE(tape.seek_backwards() == true);
|
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.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.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]") {
|
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") {
|
SECTION("Rewinding at the beginning of a file tape") {
|
||||||
REQUIRE(tape.seek_backwards() == false);
|
REQUIRE(tape.seek_backwards() == false);
|
||||||
REQUIRE(tape.read() == 1);
|
REQUIRE(tape.read() == TEST_DATA[0]);
|
||||||
REQUIRE(tape.seek_forward() == true);
|
REQUIRE(tape.seek_forward() == true);
|
||||||
REQUIRE(tape.read() == 2);
|
REQUIRE(tape.read() == TEST_DATA[1]);
|
||||||
REQUIRE(tape.seek_backwards() == true);
|
REQUIRE(tape.seek_backwards() == true);
|
||||||
REQUIRE(tape.seek_backwards() == false);
|
REQUIRE(tape.seek_backwards() == false);
|
||||||
REQUIRE(tape.read() == 1);
|
REQUIRE(tape.read() == TEST_DATA[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Seeking at the end of a file tape") {
|
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() == true);
|
||||||
}
|
}
|
||||||
REQUIRE(tape.seek_forward() == false);
|
REQUIRE(tape.seek_forward() == false);
|
||||||
REQUIRE(tape.read() == 5);
|
REQUIRE(tape.read() == TEST_DATA[4]);
|
||||||
REQUIRE(tape.seek_backwards() == true);
|
REQUIRE(tape.seek_backwards() == true);
|
||||||
REQUIRE(tape.read() == 4);
|
REQUIRE(tape.read() == TEST_DATA[3]);
|
||||||
REQUIRE(tape.seek_forward() == true);
|
REQUIRE(tape.seek_forward() == true);
|
||||||
REQUIRE(tape.seek_forward() == false);
|
REQUIRE(tape.seek_forward() == false);
|
||||||
REQUIRE(tape.read() == 5);
|
REQUIRE(tape.read() == TEST_DATA[4]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue