From 1827fe982ae6829a83bed83dd021b7c31eb76a34 Mon Sep 17 00:00:00 2001 From: seleznevae Date: Sat, 3 Nov 2018 00:16:20 +0300 Subject: [PATCH] [A] Added table copy operations --- lib/fort.c | 221 +++++++++++++++++++++++------- lib/fort.h | 11 ++ lib/fort.hpp | 42 +++++- src/cell.c | 16 +++ src/cell.h | 3 + src/fort_impl.c | 36 +++++ src/options.c | 66 +++++---- src/options.h | 8 +- src/row.c | 21 +++ src/row.h | 3 + src/string_buffer.c | 56 ++++++-- src/string_buffer.h | 5 + src/vector.c | 3 +- src/vector.h | 4 +- tests/bb_tests/test_table_basic.c | 32 +++++ 15 files changed, 428 insertions(+), 99 deletions(-) diff --git a/lib/fort.c b/lib/fort.c index e306a56..2f86b77 100644 --- a/lib/fort.c +++ b/lib/fort.c @@ -237,8 +237,10 @@ fort_status_t vector_swap(vector_t *cur_vec, vector_t *mv_vec, size_t pos); #define FOR_EACH(type, item, vector) \ FOR_EACH_(type, item, vector, UNIQUE_NAME(i)) -#ifdef FT_TEST_BUILD +FT_INTERNAL vector_t *copy_vector(vector_t *); + +#ifdef FT_TEST_BUILD size_t vector_index_of(const vector_t *, const void *item); int vector_erase(vector_t *, size_t index); void vector_clear(vector_t *); @@ -290,7 +292,9 @@ int mk_wcswidth(const wchar_t *pwcs, size_t n); * ***************************************************************************/ enum str_buf_type { CharBuf, +#ifdef FT_HAVE_WCHAR WCharBuf +#endif /* FT_HAVE_WCHAR */ }; struct string_buffer { @@ -309,6 +313,9 @@ string_buffer_t *create_string_buffer(size_t number_of_chars, enum str_buf_type FT_INTERNAL void destroy_string_buffer(string_buffer_t *buffer); +FT_INTERNAL +string_buffer_t *copy_string_buffer(string_buffer_t *buffer); + FT_INTERNAL fort_status_t realloc_string_buffer_without_copy(string_buffer_t *buffer); @@ -523,14 +530,12 @@ size_t max_border_elem_strlen(struct fort_table_options *); FT_INTERNAL fort_table_options_t *create_table_options(void); -/* -FT_INTERNAL -fort_table_options_t *copy_table_options(const fort_table_options_t *option); -*/ - FT_INTERNAL void destroy_table_options(fort_table_options_t *options); +FT_INTERNAL +fort_table_options_t *copy_table_options(const fort_table_options_t *option); + #endif /* OPTIONS_H */ /******************************************************** @@ -553,6 +558,9 @@ fort_cell_t *create_cell(void); FT_INTERNAL void destroy_cell(fort_cell_t *cell); +FT_INTERNAL +fort_cell_t *copy_cell(fort_cell_t *cell); + FT_INTERNAL size_t hint_width_cell(const fort_cell_t *cell, const context_t *context); @@ -610,6 +618,9 @@ fort_row_t *create_row(void); FT_INTERNAL void destroy_row(fort_row_t *row); +FT_INTERNAL +fort_row_t *copy_row(fort_row_t *row); + FT_INTERNAL fort_row_t *create_row_from_string(const char *str); @@ -1364,31 +1375,6 @@ fort_table_options_t *create_table_options(void) return options; } -/* -FT_INTERNAL -fort_table_options_t *copy_table_options(const fort_table_options_t *option) -{ - // todo: normal implementation, do deep copy of col options - - fort_table_options_t *new_opt = create_table_options(); - if (new_opt == NULL) - return NULL; - - memcpy(new_opt, option, sizeof(fort_table_options_t)); - - if (option->cell_options) { - destroy_cell_opt_container(new_opt->cell_options); - new_opt->cell_options = copy_vector(option->cell_options); - if (new_opt->cell_options == NULL) { - destroy_table_options(new_opt); - new_opt = NULL; - } - } - return new_opt; -} -*/ - - FT_INTERNAL void destroy_table_options(fort_table_options_t *options) { @@ -1401,6 +1387,47 @@ void destroy_table_options(fort_table_options_t *options) F_FREE(options); } +static +fort_cell_opt_container_t *copy_cell_options(fort_cell_opt_container_t *cont) +{ + fort_cell_opt_container_t *result = create_cell_opt_container(); + if (result == NULL) + return NULL; + + size_t sz = vector_size(cont); + for (size_t i = 0; i < sz; ++i) { + fort_cell_options_t *opt = (fort_cell_options_t *)vector_at(cont, i); + if (FT_IS_ERROR(vector_push(result, opt))) { + destroy_cell_opt_container(result); + return NULL; + } + } + return result; +} + +FT_INTERNAL +fort_table_options_t *copy_table_options(const fort_table_options_t *option) +{ + // todo: normal implementation, do deep copy of col options + + fort_table_options_t *new_opt = create_table_options(); + if (new_opt == NULL) + return NULL; + + destroy_vector(new_opt->cell_options); + new_opt->cell_options = copy_cell_options(option->cell_options); + if (new_opt == NULL) { + destroy_table_options(new_opt); + return NULL; + } + + memcpy(&new_opt->border_style, &option->border_style, sizeof(struct fort_border_style)); + memcpy(&new_opt->entire_table_options, + &option->entire_table_options, sizeof(fort_entire_table_options_t)); + + return new_opt; +} + @@ -1788,6 +1815,42 @@ void ft_destroy_table(ft_table_t *table) F_FREE(table); } +ft_table_t *ft_copy_table(ft_table_t *table) +{ + if (table == NULL) + return NULL; + + ft_table_t *result = ft_create_table(); + if (result == NULL) + return NULL; + + size_t rows_n = vector_size(table->rows); + for (size_t i = 0; i < rows_n; ++i) { + fort_row_t *row = *(fort_row_t **)vector_at(table->rows, i); + fort_row_t *new_row = copy_row(row); + if (new_row == NULL) { + ft_destroy_table(result); + return NULL; + } + vector_push(result->rows, &new_row); + } + + /* todo: copy separators */ + + result->options = copy_table_options(table->options); + if (result->options == NULL) { + ft_destroy_table(result); + return NULL; + } + + /* todo: copy conv_buffer ?? */ + + result->cur_row = table->cur_row; + result->cur_col = table->cur_col; + return result; +} + + void ft_ln(ft_table_t *table) { assert(table); @@ -2860,8 +2923,6 @@ fort_status_t vector_swap(vector_t *cur_vec, vector_t *mv_vec, size_t pos) return FT_SUCCESS; } - -#ifdef FT_TEST_BUILD vector_t *copy_vector(vector_t *v) { if (v == NULL) @@ -2877,6 +2938,7 @@ vector_t *copy_vector(vector_t *v) return new_vector; } +#ifdef FT_TEST_BUILD size_t vector_index_of(const vector_t *vector, const void *item) { @@ -3114,6 +3176,34 @@ void destroy_string_buffer(string_buffer_t *buffer) F_FREE(buffer); } +FT_INTERNAL +string_buffer_t *copy_string_buffer(string_buffer_t *buffer) +{ + assert(buffer); + string_buffer_t *result = create_string_buffer(buffer->data_sz, buffer->type); + if (result == NULL) + return NULL; + switch (buffer->type) { + case CharBuf: + if (FT_IS_ERROR(fill_buffer_from_string(result, buffer->str.cstr))) { + destroy_string_buffer(buffer); + return NULL; + } + break; +#ifdef FT_HAVE_WCHAR + case WCharBuf: + if (FT_IS_ERROR(fill_buffer_from_wstring(result, buffer->str.wstr))) { + destroy_string_buffer(buffer); + return NULL; + } + break; +#endif /* FT_HAVE_WCHAR */ + default: + destroy_string_buffer(result); + return NULL; + } + return result; +} FT_INTERNAL fort_status_t realloc_string_buffer_without_copy(string_buffer_t *buffer) @@ -3136,17 +3226,17 @@ fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str) assert(buffer); assert(str); - size_t sz = strlen(str); +// size_t sz = strlen(str); char *copy = F_STRDUP(str); if (copy == NULL) return FT_MEMORY_ERROR; - while (sz >= string_buffer_capacity(buffer)) { - int status = realloc_string_buffer_without_copy(buffer); - if (!FT_IS_SUCCESS(status)) { - return status; - } - } +// while (sz >= string_buffer_capacity(buffer)) { +// int status = realloc_string_buffer_without_copy(buffer); +// if (!FT_IS_SUCCESS(status)) { +// return status; +// } +// } F_FREE(buffer->str.data); buffer->str.cstr = copy; buffer->type = CharBuf; @@ -3162,17 +3252,17 @@ fort_status_t fill_buffer_from_wstring(string_buffer_t *buffer, const wchar_t *s assert(buffer); assert(str); - size_t sz = wcslen(str); +// size_t sz = wcslen(str); wchar_t *copy = F_WCSDUP(str); if (copy == NULL) return FT_MEMORY_ERROR; - while (sz >= string_buffer_capacity(buffer)) { - int status = realloc_string_buffer_without_copy(buffer); - if (!FT_IS_SUCCESS(status)) { - return status; - } - } +// while (sz >= string_buffer_capacity(buffer)) { +// int status = realloc_string_buffer_without_copy(buffer); +// if (!FT_IS_SUCCESS(status)) { +// return status; +// } +// } F_FREE(buffer->str.data); buffer->str.wstr = copy; buffer->type = WCharBuf; @@ -3768,6 +3858,27 @@ void destroy_row(fort_row_t *row) F_FREE(row); } +FT_INTERNAL +fort_row_t *copy_row(fort_row_t *row) +{ + assert(row); + fort_row_t *result = create_row(); + if (result == NULL) + return NULL; + + size_t cols_n = vector_size(row->cells); + for (size_t i = 0; i < cols_n; ++i) { + fort_cell_t *cell = *(fort_cell_t **)vector_at(row->cells, i); + fort_cell_t *new_cell = copy_cell(cell); + if (new_cell == NULL) { + destroy_row(result); + return NULL; + } + vector_push(result->cells, &new_cell); + } + + return result; +} FT_INTERNAL size_t columns_in_row(const fort_row_t *row) @@ -5076,6 +5187,22 @@ void destroy_cell(fort_cell_t *cell) F_FREE(cell); } +FT_INTERNAL +fort_cell_t *copy_cell(fort_cell_t *cell) +{ + assert(cell); + + fort_cell_t *result = create_cell(); + destroy_string_buffer(result->str_buffer); + result->str_buffer = copy_string_buffer(cell->str_buffer); + if (result->str_buffer == NULL) { + destroy_cell(result); + return NULL; + } + result->cell_type = cell->cell_type; + return result; +} + FT_INTERNAL void set_cell_type(fort_cell_t *cell, enum CellType type) { diff --git a/lib/fort.h b/lib/fort.h index c05c0f1..a9d20b4 100644 --- a/lib/fort.h +++ b/lib/fort.h @@ -244,6 +244,17 @@ ft_table_t *ft_create_table(void); */ void ft_destroy_table(ft_table_t *table); +/** + * Copy formatted table. + * + * @param table + * Pointer to formatted table previousley created with ft_create_table. If + * table is a null pointer, the function returns null. + * @return + * The pointer to the new allocated ft_table_t, on success. NULL on error. + */ +ft_table_t *ft_copy_table(ft_table_t *table); + /** * Move current position to the first cell of the next line(row). * diff --git a/lib/fort.hpp b/lib/fort.hpp index 3aba196..c0e0af9 100644 --- a/lib/fort.hpp +++ b/lib/fort.hpp @@ -106,9 +106,23 @@ public: } /** - * Not implemented yet. + * Copy contstructor. */ - Table(const Table& tbl) = delete; + Table(const Table& tbl) + :table(NULL) + { + if (tbl.table) { + ft_table_t *table_copy = ft_copy_table(tbl.table); + if (table_copy == NULL) + throw std::runtime_error("Runtime error"); + + stream.str(std::string()); + if (tbl.stream.tellp() >= 0) { + stream << tbl.stream.str(); + } + table = table_copy; + } + } /** * Move contstructor. @@ -124,9 +138,27 @@ public: } /** - * Not implemented yet. + * Copy assignment operator. */ - Table& operator=(const Table& tbl) = delete; + Table& operator=(const Table& tbl) + { + if (&tbl == this) + return *this; + + if (tbl.table) { + ft_table_t *table_copy = ft_copy_table(tbl.table); + if (table_copy == NULL) + throw std::runtime_error("Runtime error"); + + stream.str(std::string()); + if (tbl.stream.tellp() >= 0) { + stream << tbl.stream.str(); + } + ft_destroy_table(table); + table = table_copy; + } + return *this; + } /** * Move assignment operator. @@ -545,7 +577,7 @@ public: } private: ft_table_t *table; - std::stringstream stream; + mutable std::stringstream stream; public: diff --git a/src/cell.c b/src/cell.c index ee6a83a..901b7b0 100644 --- a/src/cell.c +++ b/src/cell.c @@ -32,6 +32,22 @@ void destroy_cell(fort_cell_t *cell) F_FREE(cell); } +FT_INTERNAL +fort_cell_t *copy_cell(fort_cell_t *cell) +{ + assert(cell); + + fort_cell_t *result = create_cell(); + destroy_string_buffer(result->str_buffer); + result->str_buffer = copy_string_buffer(cell->str_buffer); + if (result->str_buffer == NULL) { + destroy_cell(result); + return NULL; + } + result->cell_type = cell->cell_type; + return result; +} + FT_INTERNAL void set_cell_type(fort_cell_t *cell, enum CellType type) { diff --git a/src/cell.h b/src/cell.h index b8eb2d6..b0f4abe 100644 --- a/src/cell.h +++ b/src/cell.h @@ -9,6 +9,9 @@ fort_cell_t *create_cell(void); FT_INTERNAL void destroy_cell(fort_cell_t *cell); +FT_INTERNAL +fort_cell_t *copy_cell(fort_cell_t *cell); + FT_INTERNAL size_t hint_width_cell(const fort_cell_t *cell, const context_t *context); diff --git a/src/fort_impl.c b/src/fort_impl.c index 983c45a..0aeaaa2 100644 --- a/src/fort_impl.c +++ b/src/fort_impl.c @@ -92,6 +92,42 @@ void ft_destroy_table(ft_table_t *table) F_FREE(table); } +ft_table_t *ft_copy_table(ft_table_t *table) +{ + if (table == NULL) + return NULL; + + ft_table_t *result = ft_create_table(); + if (result == NULL) + return NULL; + + size_t rows_n = vector_size(table->rows); + for (size_t i = 0; i < rows_n; ++i) { + fort_row_t *row = *(fort_row_t **)vector_at(table->rows, i); + fort_row_t *new_row = copy_row(row); + if (new_row == NULL) { + ft_destroy_table(result); + return NULL; + } + vector_push(result->rows, &new_row); + } + + /* todo: copy separators */ + + result->options = copy_table_options(table->options); + if (result->options == NULL) { + ft_destroy_table(result); + return NULL; + } + + /* todo: copy conv_buffer ?? */ + + result->cur_row = table->cur_row; + result->cur_col = table->cur_col; + return result; +} + + void ft_ln(ft_table_t *table) { assert(table); diff --git a/src/options.c b/src/options.c index 47bca15..02c3559 100644 --- a/src/options.c +++ b/src/options.c @@ -626,31 +626,6 @@ fort_table_options_t *create_table_options(void) return options; } -/* -FT_INTERNAL -fort_table_options_t *copy_table_options(const fort_table_options_t *option) -{ - // todo: normal implementation, do deep copy of col options - - fort_table_options_t *new_opt = create_table_options(); - if (new_opt == NULL) - return NULL; - - memcpy(new_opt, option, sizeof(fort_table_options_t)); - - if (option->cell_options) { - destroy_cell_opt_container(new_opt->cell_options); - new_opt->cell_options = copy_vector(option->cell_options); - if (new_opt->cell_options == NULL) { - destroy_table_options(new_opt); - new_opt = NULL; - } - } - return new_opt; -} -*/ - - FT_INTERNAL void destroy_table_options(fort_table_options_t *options) { @@ -663,5 +638,46 @@ void destroy_table_options(fort_table_options_t *options) F_FREE(options); } +static +fort_cell_opt_container_t *copy_cell_options(fort_cell_opt_container_t *cont) +{ + fort_cell_opt_container_t *result = create_cell_opt_container(); + if (result == NULL) + return NULL; + + size_t sz = vector_size(cont); + for (size_t i = 0; i < sz; ++i) { + fort_cell_options_t *opt = (fort_cell_options_t *)vector_at(cont, i); + if (FT_IS_ERROR(vector_push(result, opt))) { + destroy_cell_opt_container(result); + return NULL; + } + } + return result; +} + +FT_INTERNAL +fort_table_options_t *copy_table_options(const fort_table_options_t *option) +{ + // todo: normal implementation, do deep copy of col options + + fort_table_options_t *new_opt = create_table_options(); + if (new_opt == NULL) + return NULL; + + destroy_vector(new_opt->cell_options); + new_opt->cell_options = copy_cell_options(option->cell_options); + if (new_opt == NULL) { + destroy_table_options(new_opt); + return NULL; + } + + memcpy(&new_opt->border_style, &option->border_style, sizeof(struct fort_border_style)); + memcpy(&new_opt->entire_table_options, + &option->entire_table_options, sizeof(fort_entire_table_options_t)); + + return new_opt; +} + diff --git a/src/options.h b/src/options.h index 99e1279..615b27c 100644 --- a/src/options.h +++ b/src/options.h @@ -170,12 +170,10 @@ size_t max_border_elem_strlen(struct fort_table_options *); FT_INTERNAL fort_table_options_t *create_table_options(void); -/* -FT_INTERNAL -fort_table_options_t *copy_table_options(const fort_table_options_t *option); -*/ - FT_INTERNAL void destroy_table_options(fort_table_options_t *options); +FT_INTERNAL +fort_table_options_t *copy_table_options(const fort_table_options_t *option); + #endif /* OPTIONS_H */ diff --git a/src/row.c b/src/row.c index 80dae7e..90190a3 100644 --- a/src/row.c +++ b/src/row.c @@ -49,6 +49,27 @@ void destroy_row(fort_row_t *row) F_FREE(row); } +FT_INTERNAL +fort_row_t *copy_row(fort_row_t *row) +{ + assert(row); + fort_row_t *result = create_row(); + if (result == NULL) + return NULL; + + size_t cols_n = vector_size(row->cells); + for (size_t i = 0; i < cols_n; ++i) { + fort_cell_t *cell = *(fort_cell_t **)vector_at(row->cells, i); + fort_cell_t *new_cell = copy_cell(cell); + if (new_cell == NULL) { + destroy_row(result); + return NULL; + } + vector_push(result->cells, &new_cell); + } + + return result; +} FT_INTERNAL size_t columns_in_row(const fort_row_t *row) diff --git a/src/row.h b/src/row.h index 76ee59b..614bd1e 100644 --- a/src/row.h +++ b/src/row.h @@ -15,6 +15,9 @@ fort_row_t *create_row(void); FT_INTERNAL void destroy_row(fort_row_t *row); +FT_INTERNAL +fort_row_t *copy_row(fort_row_t *row); + FT_INTERNAL fort_row_t *create_row_from_string(const char *str); diff --git a/src/string_buffer.c b/src/string_buffer.c index 818234b..f729426 100644 --- a/src/string_buffer.c +++ b/src/string_buffer.c @@ -188,6 +188,34 @@ void destroy_string_buffer(string_buffer_t *buffer) F_FREE(buffer); } +FT_INTERNAL +string_buffer_t *copy_string_buffer(string_buffer_t *buffer) +{ + assert(buffer); + string_buffer_t *result = create_string_buffer(buffer->data_sz, buffer->type); + if (result == NULL) + return NULL; + switch (buffer->type) { + case CharBuf: + if (FT_IS_ERROR(fill_buffer_from_string(result, buffer->str.cstr))) { + destroy_string_buffer(buffer); + return NULL; + } + break; +#ifdef FT_HAVE_WCHAR + case WCharBuf: + if (FT_IS_ERROR(fill_buffer_from_wstring(result, buffer->str.wstr))) { + destroy_string_buffer(buffer); + return NULL; + } + break; +#endif /* FT_HAVE_WCHAR */ + default: + destroy_string_buffer(result); + return NULL; + } + return result; +} FT_INTERNAL fort_status_t realloc_string_buffer_without_copy(string_buffer_t *buffer) @@ -210,17 +238,17 @@ fort_status_t fill_buffer_from_string(string_buffer_t *buffer, const char *str) assert(buffer); assert(str); - size_t sz = strlen(str); +// size_t sz = strlen(str); char *copy = F_STRDUP(str); if (copy == NULL) return FT_MEMORY_ERROR; - while (sz >= string_buffer_capacity(buffer)) { - int status = realloc_string_buffer_without_copy(buffer); - if (!FT_IS_SUCCESS(status)) { - return status; - } - } +// while (sz >= string_buffer_capacity(buffer)) { +// int status = realloc_string_buffer_without_copy(buffer); +// if (!FT_IS_SUCCESS(status)) { +// return status; +// } +// } F_FREE(buffer->str.data); buffer->str.cstr = copy; buffer->type = CharBuf; @@ -236,17 +264,17 @@ fort_status_t fill_buffer_from_wstring(string_buffer_t *buffer, const wchar_t *s assert(buffer); assert(str); - size_t sz = wcslen(str); +// size_t sz = wcslen(str); wchar_t *copy = F_WCSDUP(str); if (copy == NULL) return FT_MEMORY_ERROR; - while (sz >= string_buffer_capacity(buffer)) { - int status = realloc_string_buffer_without_copy(buffer); - if (!FT_IS_SUCCESS(status)) { - return status; - } - } +// while (sz >= string_buffer_capacity(buffer)) { +// int status = realloc_string_buffer_without_copy(buffer); +// if (!FT_IS_SUCCESS(status)) { +// return status; +// } +// } F_FREE(buffer->str.data); buffer->str.wstr = copy; buffer->type = WCharBuf; diff --git a/src/string_buffer.h b/src/string_buffer.h index a3725fa..e700916 100644 --- a/src/string_buffer.h +++ b/src/string_buffer.h @@ -9,7 +9,9 @@ * ***************************************************************************/ enum str_buf_type { CharBuf, +#ifdef FT_HAVE_WCHAR WCharBuf +#endif /* FT_HAVE_WCHAR */ }; struct string_buffer { @@ -28,6 +30,9 @@ string_buffer_t *create_string_buffer(size_t number_of_chars, enum str_buf_type FT_INTERNAL void destroy_string_buffer(string_buffer_t *buffer); +FT_INTERNAL +string_buffer_t *copy_string_buffer(string_buffer_t *buffer); + FT_INTERNAL fort_status_t realloc_string_buffer_without_copy(string_buffer_t *buffer); diff --git a/src/vector.c b/src/vector.c index fe242be..82d23e8 100644 --- a/src/vector.c +++ b/src/vector.c @@ -178,8 +178,6 @@ fort_status_t vector_swap(vector_t *cur_vec, vector_t *mv_vec, size_t pos) return FT_SUCCESS; } - -#ifdef FT_TEST_BUILD vector_t *copy_vector(vector_t *v) { if (v == NULL) @@ -195,6 +193,7 @@ vector_t *copy_vector(vector_t *v) return new_vector; } +#ifdef FT_TEST_BUILD size_t vector_index_of(const vector_t *vector, const void *item) { diff --git a/src/vector.h b/src/vector.h index a460a84..adb0047 100644 --- a/src/vector.h +++ b/src/vector.h @@ -38,8 +38,10 @@ fort_status_t vector_swap(vector_t *cur_vec, vector_t *mv_vec, size_t pos); #define FOR_EACH(type, item, vector) \ FOR_EACH_(type, item, vector, UNIQUE_NAME(i)) -#ifdef FT_TEST_BUILD +FT_INTERNAL vector_t *copy_vector(vector_t *); + +#ifdef FT_TEST_BUILD size_t vector_index_of(const vector_t *, const void *item); int vector_erase(vector_t *, size_t index); void vector_clear(vector_t *); diff --git a/tests/bb_tests/test_table_basic.c b/tests/bb_tests/test_table_basic.c index ed878e2..afc00f2 100644 --- a/tests/bb_tests/test_table_basic.c +++ b/tests/bb_tests/test_table_basic.c @@ -68,6 +68,38 @@ void test_table_basic(void) } #endif + WHEN("Test table copy") { + table = ft_create_table(); + assert_true(table != NULL); + assert_true(set_test_options_for_table(table) == FT_SUCCESS); + + ft_set_cell_option(table, 0, FT_ANY_COLUMN, FT_COPT_ROW_TYPE, FT_ROW_HEADER); + assert_true(ft_write_ln(table, "3", "c", "234", "3.140000") == FT_SUCCESS); + assert_true(ft_write_ln(table, "3", "c", "234", "3.140000") == FT_SUCCESS); + assert_true(ft_write_ln(table, "3", "c", "234", "3.140000") == FT_SUCCESS); + + ft_table_t *table_copy = ft_copy_table(table); + assert_true(table != NULL); + const char *table_str = ft_to_string(table_copy); + assert_true(table_str != NULL); + const char *table_str_etalon = + "+---+---+-----+----------+\n" + "| | | | |\n" + "| 3 | c | 234 | 3.140000 |\n" + "| | | | |\n" + "+---+---+-----+----------+\n" + "| | | | |\n" + "| 3 | c | 234 | 3.140000 |\n" + "| | | | |\n" + "+---+---+-----+----------+\n" + "| | | | |\n" + "| 3 | c | 234 | 3.140000 |\n" + "| | | | |\n" + "+---+---+-----+----------+\n"; + assert_str_equal(table_str, table_str_etalon); + ft_destroy_table(table); + ft_destroy_table(table_copy); + } WHEN("All columns are not equal and not empty") {