From 400c8bc0849fe832fbe7f97490e8d65357176100 Mon Sep 17 00:00:00 2001 From: smolBlackCat <66385489+smolBlackCat@users.noreply.github.com> Date: Thu, 31 Oct 2024 19:04:11 -0300 Subject: [PATCH] (core): Implement late initialisation to Board * Rename operation methods --- src/core/board.cpp | 321 +++++++++++++++++--------------- src/core/board.h | 26 ++- src/core/card.cpp | 6 +- src/core/card.h | 6 +- src/core/cardlist.cpp | 6 +- src/core/cardlist.h | 6 +- src/dialog/card-dialog.cpp | 6 +- src/widgets/board-widget.cpp | 8 +- src/widgets/cardlist-widget.cpp | 6 +- test/board-test.cpp | 107 ++++++++--- test/card-test.cpp | 26 +-- test/cardlist-test.cpp | 24 +-- test/modification-test.cpp | 18 +- 13 files changed, 337 insertions(+), 229 deletions(-) diff --git a/src/core/board.cpp b/src/core/board.cpp index 6662f18..5c23fa9 100644 --- a/src/core/board.cpp +++ b/src/core/board.cpp @@ -1,17 +1,11 @@ #include "board.h" -#include - -#include #include -#include #include #include #include #include #include -#include -#include #include "exceptions.h" @@ -90,90 +84,7 @@ Board BoardBackend::load() { board.last_modified = std::chrono::floor(lm_filepath); - auto list_element = board_element->FirstChildElement("list"); - - while (list_element) { - auto cur_cardlist_name = list_element->Attribute("name"); - - if (!cur_cardlist_name) { - throw board_parse_error{std::format( - "Failed to parse given Progress Board XML file: {}\n" - "A \"list\" element on line {} failed to parsed.", - settings["filepath"], list_element->GetLineNum())}; - } - - CardList cur_cardlist{cur_cardlist_name}; - auto card_element = list_element->FirstChildElement("card"); - - while (card_element) { - auto cur_card_name = card_element->Attribute("name"); - auto cur_card_color = card_element->Attribute("color"); - auto cur_card_due_date = card_element->Attribute("due"); - auto cur_card_complete = - card_element->BoolAttribute("complete"); - - if (!cur_card_name) { - throw board_parse_error{std::format( - "Failed to parse given Progress Board XML file: " - "{}\n" - "Failed to load {} \"list\" element\n" - "\"card\" element on line {} has no name attribute", - settings["filepath"], cur_cardlist_name, - card_element->GetLineNum())}; - } - - Date date{}; - - if (cur_card_due_date) { - const std::regex date_r{"\\d\\d\\d\\d-\\d\\d-\\d\\d"}; - - if (!std::regex_match(cur_card_due_date, date_r)) { - throw board_parse_error{std::format( - "Invalid due date at Card {}", cur_card_name)}; - } - std::chrono::sys_seconds secs; - - std::istringstream{std::string{cur_card_due_date}} >> - std::chrono::parse("%F", secs); - Date date{std::chrono::floor(secs)}; - date = date; - } - - Card cur_card{ - cur_card_name, - date, - cur_card_complete, - cur_card_color ? string_to_color(cur_card_color) - : NO_COLOR, - }; - - auto task_element = card_element->FirstChildElement("task"); - while (task_element) { - cur_card.add_task( - Task{task_element->Attribute("name"), - task_element->BoolAttribute("done")}); - task_element = task_element->NextSiblingElement("task"); - } - - auto notes_element = - card_element->FirstChildElement("notes"); - if (notes_element) { - cur_card.set_notes(!notes_element->GetText() - ? "" - : notes_element->GetText()); - } - - cur_card.set_modified(false); - - cur_cardlist.add_card(cur_card); - card_element = card_element->NextSiblingElement("card"); - } - cur_cardlist.set_modified(false); - board.add_cardlist(cur_cardlist); - - list_element = list_element->NextSiblingElement("list"); - } - board.set_modified(false); + board.modified = false; return board; } case BackendType::CALDAV: @@ -185,10 +96,14 @@ Board BoardBackend::load() { Board BoardBackend::create(const std::string& name, const std::string& background) { Board board{*this}; + + // Because a new Board is created from scratch, it is essentially loaded + board.fully_loaded = true; + board.set_name(name); board.set_background(background); - board.set_modified(false); + return board; } @@ -217,13 +132,106 @@ bool BoardBackend::set_attribute(const std::string& key, } bool BoardBackend::save(Board& board) { - switch (type) { - case BackendType::LOCAL: - return save_xml(board); - case BackendType::CALDAV: - return save_caldav(board); - case BackendType::NEXTCLOUD: - return save_nextcloud(board); + if (board.fully_loaded) { + switch (type) { + case BackendType::LOCAL: + return save_xml(board); + case BackendType::CALDAV: + return save_caldav(board); + case BackendType::NEXTCLOUD: + return save_nextcloud(board); + } + } + return false; +} + +void BoardBackend::load_cardlists(Board& board) { + if (!board.fully_loaded) { + tinyxml2::XMLDocument doc; + doc.LoadFile(settings["filepath"].c_str()); + board.fully_loaded = true; + auto list_element = + doc.FirstChildElement("board")->FirstChildElement("list"); + + while (list_element) { + auto cur_cardlist_name = list_element->Attribute("name"); + + if (!cur_cardlist_name) { + throw board_parse_error{std::format( + "Failed to parse given Progress Board XML file: {}\n" + "A \"list\" element on line {} failed to parsed.", + settings["filepath"], list_element->GetLineNum())}; + } + + CardList cur_cardlist{cur_cardlist_name}; + auto card_element = list_element->FirstChildElement("card"); + + while (card_element) { + auto cur_card_name = card_element->Attribute("name"); + auto cur_card_color = card_element->Attribute("color"); + auto cur_card_due_date = card_element->Attribute("due"); + auto cur_card_complete = + card_element->BoolAttribute("complete"); + + if (!cur_card_name) { + throw board_parse_error{std::format( + "Failed to parse given Progress Board XML file: " + "{}\n" + "Failed to load {} \"list\" element\n" + "\"card\" element on line {} has no name attribute", + settings["filepath"], cur_cardlist_name, + card_element->GetLineNum())}; + } + + Date date{}; + + if (cur_card_due_date) { + const std::regex date_r{"\\d\\d\\d\\d-\\d\\d-\\d\\d"}; + + if (!std::regex_match(cur_card_due_date, date_r)) { + throw board_parse_error{std::format( + "Invalid due date at Card {}", cur_card_name)}; + } + std::chrono::sys_seconds secs; + + std::istringstream{std::string{cur_card_due_date}} >> + std::chrono::parse("%F", secs); + Date date{std::chrono::floor(secs)}; + date = date; + } + + Card cur_card{ + cur_card_name, + date, + cur_card_complete, + cur_card_color ? string_to_color(cur_card_color) : NO_COLOR, + }; + + auto task_element = card_element->FirstChildElement("task"); + while (task_element) { + cur_card.add(Task{task_element->Attribute("name"), + task_element->BoolAttribute("done")}); + task_element = task_element->NextSiblingElement("task"); + } + + auto notes_element = card_element->FirstChildElement("notes"); + if (notes_element) { + cur_card.set_notes(!notes_element->GetText() + ? "" + : notes_element->GetText()); + } + + cur_card.set_modified(false); + + cur_cardlist.add(cur_card); + card_element = card_element->NextSiblingElement("card"); + } + cur_cardlist.set_modified(false); + board.add(cur_cardlist); + + list_element = list_element->NextSiblingElement("list"); + } + board.set_modified(false); } } @@ -313,83 +321,96 @@ BackgroundType Board::set_background(const std::string& other, bool modify) { const std::string& Board::get_background() const { return background; } -std::shared_ptr Board::add_cardlist(const CardList& cardlist) { - for (auto& ccardlist : cardlists) { - if (*ccardlist == cardlist) { - return nullptr; +std::shared_ptr Board::add(const CardList& cardlist) { + if (fully_loaded) { + for (auto& ccardlist : cardlists) { + if (*ccardlist == cardlist) { + return nullptr; + } } - } - try { - std::shared_ptr new_cardlist = - std::make_shared(cardlist); - cardlists.push_back(new_cardlist); - modified = true; - return new_cardlist; - } catch (std::bad_alloc& err) { - return nullptr; + try { + std::shared_ptr new_cardlist = + std::make_shared(cardlist); + cardlists.push_back(new_cardlist); + modified = true; + return new_cardlist; + } catch (std::bad_alloc& err) { + return nullptr; + } } + return nullptr; } -bool Board::remove_cardlist(const CardList& cardlist) { - for (size_t i = 0; i < cardlists.size(); i++) { - if (cardlist == (*cardlists.at(i))) { - cardlists.erase(cardlists.begin() + i); - modified = true; - return true; +bool Board::remove(const CardList& cardlist) { + if (fully_loaded) { + for (size_t i = 0; i < cardlists.size(); i++) { + if (cardlist == (*cardlists.at(i))) { + cardlists.erase(cardlists.begin() + i); + modified = true; + return true; + } } } return false; } -void Board::reorder_cardlist(const CardList& next, const CardList& sibling) { - ssize_t next_i = -1; - ssize_t sibling_i = -1; - - for (ssize_t i = 0; i < cardlists.size(); i++) { - if (*cardlists[i] == next) { - next_i = i; - } else if (*cardlists[i] == sibling) { - sibling_i = i; +void Board::reorder(const CardList& next, const CardList& sibling) { + if (fully_loaded) { + ssize_t next_i = -1; + ssize_t sibling_i = -1; + + ssize_t c = 0; + for (auto& cardlist : cardlists) { + if (*cardlist == next) { + next_i = c; + } else if (*cardlist == sibling) { + sibling_i = c; + } + c++; } - } - bool any_absent_item = next_i + sibling_i < 0; - bool is_same_item = next_i == sibling_i; - bool already_in_order = next_i - sibling_i == 1; - if (any_absent_item || is_same_item || already_in_order) { - return; - } + bool any_absent_item = next_i + sibling_i < 0; + bool is_same_item = next_i == sibling_i; + bool already_in_order = next_i - sibling_i == 1; + if (any_absent_item || is_same_item || already_in_order) { + return; + } - auto next_it = std::next(cardlists.begin(), next_i); - std::shared_ptr temp_v = cardlists[next_i]; - cardlists.erase(next_it); + auto next_it = std::next(cardlists.begin(), next_i); + std::shared_ptr temp_v = cardlists[next_i]; + cardlists.erase(next_it); - // Support for right to left drags and drops - if (next_i < sibling_i) { - sibling_i -= 1; - } + // Support for right to left drags and drops + if (next_i < sibling_i) { + sibling_i -= 1; + } - if (sibling_i == cardlists.size() - 1) { - cardlists.push_back(temp_v); - } else { - auto sibling_it = std::next(cardlists.begin(), sibling_i + 1); - cardlists.insert(sibling_it, temp_v); + if (sibling_i == cardlists.size() - 1) { + cardlists.push_back(temp_v); + } else { + auto sibling_it = std::next(cardlists.begin(), sibling_i + 1); + cardlists.insert(sibling_it, temp_v); + } + modified = true; } - modified = true; } bool Board::save() { return backend.save(*this); } +void Board::load() { backend.load_cardlists(*this); } + const std::vector>& Board::get_cardlists() { return cardlists; } void Board::set_modified(bool modified) { - Item::set_modified(modified); + if (fully_loaded) { + Item::set_modified(modified); - for (auto& cardlist : cardlists) { - cardlist->set_modified(modified); + for (auto& cardlist : cardlists) { + cardlist->set_modified(modified); + } } } @@ -397,6 +418,8 @@ time_point Board::get_last_modified() const { return last_modified; } +bool Board::is_loaded() { return fully_loaded; } + bool Board::get_modified() { for (auto& cardlist : cardlists) { if (cardlist->get_modified()) { diff --git a/src/core/board.h b/src/core/board.h index 89cb31a..8525821 100644 --- a/src/core/board.h +++ b/src/core/board.h @@ -2,9 +2,9 @@ #include +#include #include #include -#include #include "cardlist.h" #include "item.h" @@ -62,6 +62,12 @@ class BoardBackend { */ bool save(Board& board); + /** + * @brief Load cardlists into board. The second call to this function won't + * do anything since it is expected that the board is fully loaded + */ + void load_cardlists(Board& board); + BackendType get_type() const noexcept; protected: @@ -114,7 +120,7 @@ class Board : public Item { * @returns a CardList pointer to the newly allocated object. nullptr may be * returned if the cardlist to be added is already in cardlists */ - std::shared_ptr add_cardlist(const CardList& cardlist); + std::shared_ptr add(const CardList& cardlist); /** * @brief Removes a CardList object from the board and free the allocated @@ -124,18 +130,23 @@ class Board : public Item { * False is returned if the CardList object requested to be * removed isn't in the board. */ - bool remove_cardlist(const CardList& cardlist); + bool remove(const CardList& cardlist); /** * @brief Reorders cardlist "next" after cardlist "sibling" */ - void reorder_cardlist(const CardList& next, const CardList& sibling); + void reorder(const CardList& next, const CardList& sibling); /** * @brief Saves the board using the backend functionality */ bool save(); + /** + * @brief Load the remaining data (cardlists) + */ + void load(); + /** * @brief Access the underlying cardlists collection */ @@ -153,6 +164,11 @@ class Board : public Item { */ bool get_modified() override; + /** + * @brief Returns true if the cardlists are loaded, otherwise false. + */ + bool is_loaded(); + /** * @brief Returns the type of a given background * @@ -168,4 +184,6 @@ class Board : public Item { std::string background; std::vector> cardlists; time_point last_modified; + + bool fully_loaded = false; }; \ No newline at end of file diff --git a/src/core/card.cpp b/src/core/card.cpp index 66023ac..dfcb7a8 100644 --- a/src/core/card.cpp +++ b/src/core/card.cpp @@ -50,7 +50,7 @@ double Card::get_completion() const { return (tasks_completed_n * 100) / tasks.size(); } -std::shared_ptr Card::add_task(const Task& task) { +std::shared_ptr Card::add(const Task& task) { for (auto& ctask : tasks) { if (task == *ctask) return nullptr; } @@ -63,7 +63,7 @@ std::shared_ptr Card::add_task(const Task& task) { return new_task; } -bool Card::remove_task(const Task& task) { +bool Card::remove(const Task& task) { for (size_t i = 0; i < tasks.size(); i++) { if (*tasks[i] == task) { tasks.erase(tasks.begin() + i); @@ -76,7 +76,7 @@ bool Card::remove_task(const Task& task) { std::vector> const& Card::get_tasks() { return tasks; } -void Card::reorder_task(const Task& next, const Task& sibling) { +void Card::reorder(const Task& next, const Task& sibling) { ssize_t next_i = -1; ssize_t sibling_i = -1; diff --git a/src/core/card.h b/src/core/card.h index 2df1d31..6f5dcc1 100644 --- a/src/core/card.h +++ b/src/core/card.h @@ -69,7 +69,7 @@ class Card : public Colorable, public Item { * returned if the caller is trying to add a Task that is already in the * Card */ - std::shared_ptr add_task(const Task& task); + std::shared_ptr add(const Task& task); /** * @brief Removes a Task object @@ -79,7 +79,7 @@ class Card : public Colorable, public Item { * @return True when the object is removed. False is returned if task is not * in tasks */ - bool remove_task(const Task& task); + bool remove(const Task& task); /** * @brief Access the underlying Task collection @@ -89,7 +89,7 @@ class Card : public Colorable, public Item { /** * @brief Put task "next" after task "sibling" */ - void reorder_task(const Task& next, const Task& sibling); + void reorder(const Task& next, const Task& sibling); /** * @brief Returns true if this card is past due date and the date is valid, diff --git a/src/core/cardlist.cpp b/src/core/cardlist.cpp index b8fa195..a378d7b 100644 --- a/src/core/cardlist.cpp +++ b/src/core/cardlist.cpp @@ -5,7 +5,7 @@ CardList::CardList(const std::string& name) : Item{name}, cards{} {} -std::shared_ptr CardList::add_card(const Card& card) { +std::shared_ptr CardList::add(const Card& card) { std::shared_ptr new_card{new Card{card}}; if (new_card) { cards.push_back(new_card); @@ -14,7 +14,7 @@ std::shared_ptr CardList::add_card(const Card& card) { return new_card; } -bool CardList::remove_card(const Card& card) { +bool CardList::remove(const Card& card) { for (size_t i = 0; i < cards.size(); i++) { if (card == *cards.at(i)) { cards.erase(cards.begin() + i); @@ -48,7 +48,7 @@ const std::vector>& CardList::get_cards() { return cards; } -void CardList::reorder_card(const Card& next, const Card& sibling) { +void CardList::reorder(const Card& next, const Card& sibling) { ssize_t next_i = -1; ssize_t sibling_i = -1; diff --git a/src/core/cardlist.h b/src/core/cardlist.h index 3a214e6..dfd1cfe 100644 --- a/src/core/cardlist.h +++ b/src/core/cardlist.h @@ -23,7 +23,7 @@ class CardList : public Item { * @returns A pointer to the allocated object. It may be nullptr if the card * being added is already in the cardlist */ - std::shared_ptr add_card(const Card& card); + std::shared_ptr add(const Card& card); /** * @brief Removes a Card object from the cardlist. @@ -34,7 +34,7 @@ class CardList : public Item { * False may be returned when the requested Card to be removed is * not present in the cardlist. */ - bool remove_card(const Card& card); + bool remove(const Card& card); void set_modified(bool modified) override; @@ -48,7 +48,7 @@ class CardList : public Item { /** * @brief Reorders card "next" after card "sibling" */ - void reorder_card(const Card& next, const Card& sibling); + void reorder(const Card& next, const Card& sibling); private: bool cards_modified(); diff --git a/src/dialog/card-dialog.cpp b/src/dialog/card-dialog.cpp index 3724f33..254112e 100644 --- a/src/dialog/card-dialog.cpp +++ b/src/dialog/card-dialog.cpp @@ -80,7 +80,7 @@ CardDetailsDialog::~CardDetailsDialog() {} void CardDetailsDialog::remove_task(TaskWidget& task) { auto card = card_widget.get_card(); - card->remove_task(*task.get_task()); + card->remove(*task.get_task()); tasks_box->remove(task); card_widget.update_complete_tasks(); } @@ -88,7 +88,7 @@ void CardDetailsDialog::remove_task(TaskWidget& task) { void CardDetailsDialog::reorder_task_widget(TaskWidget& next, TaskWidget& sibling) { tasks_box->reorder_child_after(next, sibling); - card_widget.get_card()->reorder_task(*next.get_task(), *sibling.get_task()); + card_widget.get_card()->reorder(*next.get_task(), *sibling.get_task()); } void CardDetailsDialog::open(Gtk::Window& parent) { @@ -114,7 +114,7 @@ void CardDetailsDialog::update_due_date_label() { CardWidget& CardDetailsDialog::get_card_widget() { return card_widget; } void CardDetailsDialog::on_add_task() { - _add_task(card_widget.get_card()->add_task(Task{_("New Task")}), true); + _add_task(card_widget.get_card()->add(Task{_("New Task")}), true); card_widget.update_complete_tasks(); } diff --git a/src/widgets/board-widget.cpp b/src/widgets/board-widget.cpp index 44d3d33..0f1ac18 100644 --- a/src/widgets/board-widget.cpp +++ b/src/widgets/board-widget.cpp @@ -84,6 +84,8 @@ void ui::BoardWidget::set(std::shared_ptr& board, this->board = board; this->board_card_button = board_card_button; + board->load(); + for (auto& cardlist : board->get_cardlists()) { auto new_cardlist = Gtk::make_managed(*this, cardlist); @@ -120,7 +122,7 @@ bool ui::BoardWidget::save(bool free) { ui::CardlistWidget* ui::BoardWidget::add_cardlist(const CardList& cardlist, bool editing_mode) { auto new_cardlist = Gtk::make_managed( - *this, board->add_cardlist(cardlist), editing_mode); + *this, board->add(cardlist), editing_mode); cardlist_vector.push_back(new_cardlist); root.append(*new_cardlist); @@ -132,13 +134,13 @@ ui::CardlistWidget* ui::BoardWidget::add_cardlist(const CardList& cardlist, bool ui::BoardWidget::remove_cardlist(ui::CardlistWidget& cardlist) { root.remove(cardlist); std::erase(cardlist_vector, &cardlist); - board->remove_cardlist(*cardlist.get_cardlist()); + board->remove(*cardlist.get_cardlist()); return true; } void ui::BoardWidget::reorder_cardlist(CardlistWidget& next, CardlistWidget& sibling) { - board->reorder_cardlist(*next.get_cardlist(), *sibling.get_cardlist()); + board->reorder(*next.get_cardlist(), *sibling.get_cardlist()); root.reorder_child_after(next, sibling); } diff --git a/src/widgets/cardlist-widget.cpp b/src/widgets/cardlist-widget.cpp index aabeb28..6873999 100644 --- a/src/widgets/cardlist-widget.cpp +++ b/src/widgets/cardlist-widget.cpp @@ -86,7 +86,7 @@ ui::CardlistWidget::~CardlistWidget() {} void ui::CardlistWidget::reorder_cardwidget(ui::CardWidget& next, ui::CardWidget& sibling) { root.reorder_child_after(next, sibling); - cardlist->reorder_card(*next.get_card(), *sibling.get_card()); + cardlist->reorder(*next.get_card(), *sibling.get_card()); } const std::vector& @@ -180,7 +180,7 @@ void ui::CardlistWidget::setup_drag_and_drop() { void ui::CardlistWidget::remove_card(ui::CardWidget* card) { root.remove(*card); - cardlist->remove_card(*card->get_card()); + cardlist->remove(*card->get_card()); for (size_t i = 0; i < cards_tracker.size(); i++) { if (cards_tracker[i] == card) { @@ -194,7 +194,7 @@ ui::CardWidget* ui::CardlistWidget::add_card(const Card& card, auto card_builder = Gtk::Builder::create_from_resource( "/io/github/smolblackcat/Progress/card-widget.ui"); auto new_card = Gtk::manage(Gtk::Builder::get_widget_derived( - card_builder, "card-root", cardlist->add_card(card), editing_mode)); + card_builder, "card-root", cardlist->add(card), editing_mode)); new_card->set_cardlist(this); cards_tracker.push_back(new_card); diff --git a/test/board-test.cpp b/test/board-test.cpp index a077670..0e79291 100644 --- a/test/board-test.cpp +++ b/test/board-test.cpp @@ -151,7 +151,8 @@ TEST_CASE("Invalid XML Board: missing 'name' attribute in ", "[Board]") { BoardBackend backend{BackendType::LOCAL}; backend.set_attribute("filepath", "test-board.xml"); - CHECK_THROWS(backend.load()); + Board board = backend.load(); + CHECK_THROWS(board.load()); std::filesystem::remove("test-board.xml"); } @@ -175,7 +176,8 @@ TEST_CASE("Invalid XML Board: missing 'name' attribute in ", "[Board]") { BoardBackend backend{BackendType::LOCAL}; backend.set_attribute("filepath", "test-board.xml"); - CHECK_THROWS(backend.load()); + Board board = backend.load(); + CHECK_THROWS(board.load()); std::filesystem::remove("test-board.xml"); } @@ -199,7 +201,9 @@ TEST_CASE("Invalid XML Board: malformed due date in ", "[Board]") { BoardBackend backend{BackendType::LOCAL}; backend.set_attribute("filepath", "test-board.xml"); - CHECK_THROWS(backend.load()); // Assuming load handles date parsing exception + + Board board = backend.load(); + CHECK_THROWS(board.load()); std::filesystem::remove("test-board.xml"); } @@ -225,12 +229,73 @@ TEST_CASE("Invalid XML Board: missing 'name' attribute in ", "[Board]") { BoardBackend backend{BackendType::LOCAL}; backend.set_attribute("filepath", "test-board.xml"); - CHECK_THROWS(backend.load()); + Board board = backend.load(); + CHECK_THROWS(board.load()); std::filesystem::remove("test-board.xml"); } -// TODO: Exhaust Board XML syntax tests +TEST_CASE("Board late loading", "[Board]") { + using namespace tinyxml2; + using namespace std; + + XMLDocument doc; + XMLElement* board_element = doc.NewElement("board"); + board_element->SetAttribute("name", "Progress Board"); + board_element->SetAttribute("background", "rgb(1,1,1)"); + + // Adding Valid Cardlists + for (int i = 0; i < 10; i++) { + XMLElement* list_element = board_element->InsertNewChildElement("list"); + list_element->SetAttribute("name", + std::format("Cardlist {}", i).c_str()); + // Adding valid cards + for (int j = 0; j < 10; j++) { + XMLElement* card_element = + list_element->InsertNewChildElement("card"); + card_element->SetAttribute("name", + std::format("Card {}", j).c_str()); + card_element->SetAttribute("color", "rgb(23,12,45)"); + card_element->SetAttribute("due", "1969-01-01"); + card_element->SetAttribute("complete", false); + + // Adding valid tasks to the current card + for (int k = 0; k < 10; k++) { + XMLElement* task_element = + card_element->InsertNewChildElement("task"); + task_element->SetAttribute("name", + std::format("Task {}", k).c_str()); + task_element->SetAttribute("done", true); + } + + XMLElement* notes_element = + card_element->InsertNewChildElement("notes"); + notes_element->SetText("I'm pretty loaded really yay"); + } + } + + doc.InsertFirstChild(board_element); + doc.SaveFile("test-board.xml"); + + BoardBackend backend{BackendType::LOCAL}; + REQUIRE(backend.set_attribute("filepath", "test-board.xml")); + Board board = backend.load(); + + // Basic properties must be available + CHECK(board.get_name() == "Progress Board"); + CHECK(board.get_background() == "rgb(1,1,1)"); + CHECK(!board.get_modified()); + + CHECK(!board.is_loaded()); + CHECK(board.get_cardlists().empty()); + + board.load(); + + CHECK(board.is_loaded()); + CHECK(board.get_cardlists().size() == 10); + + filesystem::remove("test-board.xml"); +} TEST_CASE("Adding Cardlists to a Board", "[Board]") { BoardBackend backend{BackendType::LOCAL}; @@ -243,15 +308,15 @@ TEST_CASE("Adding Cardlists to a Board", "[Board]") { CardList cardlist1{"TODO"}; CardList cardlist2{"TODO"}; - auto added_cardlist = board.add_cardlist(cardlist1); - auto added_cardlist2 = board.add_cardlist(cardlist2); + auto added_cardlist = board.add(cardlist1); + auto added_cardlist2 = board.add(cardlist2); REQUIRE(added_cardlist); REQUIRE(added_cardlist2); // We're trying to add the exact same cardlist again. Don't and return // nullptr - CHECK(!board.add_cardlist(cardlist1)); + CHECK(!board.add(cardlist1)); CHECK(board.get_modified()); CHECK(board.get_cardlists().size() == 2); @@ -265,15 +330,15 @@ TEST_CASE("Removing cardlists of a Board", "[Board]") { CardList cardlist1{"Something else to be done"}; - board.add_cardlist(cardlist1); + board.add(cardlist1); board.set_modified(false); - CHECK(board.remove_cardlist(cardlist1)); + CHECK(board.remove(cardlist1)); CHECK(board.get_modified()); board.set_modified(false); - CHECK(!board.remove_cardlist(cardlist1)); + CHECK(!board.remove(cardlist1)); CHECK(!board.get_modified()); } @@ -281,16 +346,16 @@ TEST_CASE("Reordering Cardlists", "Board") { Board board = BoardBackend{BackendType::LOCAL}.create("Progress", "file.png"); - auto cardlist1 = board.add_cardlist(CardList{"CardList 1"}); - auto cardlist2 = board.add_cardlist(CardList{"CardList 2"}); - auto cardlist3 = board.add_cardlist(CardList{"CardList 3"}); + auto cardlist1 = board.add(CardList{"CardList 1"}); + auto cardlist2 = board.add(CardList{"CardList 2"}); + auto cardlist3 = board.add(CardList{"CardList 3"}); auto& cardlists = board.get_cardlists(); board.set_modified(false); SECTION("Reordering using the same object references") { - board.reorder_cardlist(*cardlist1, *cardlist1); + board.reorder(*cardlist1, *cardlist1); // Because we're trying to reorder the same thing, no reordering is // done, thus no modification either @@ -303,7 +368,7 @@ TEST_CASE("Reordering Cardlists", "Board") { board.set_modified(false); SECTION("Reordering with one absent cardlist") { - board.reorder_cardlist(*cardlist1, CardList{"nobody here"}); + board.reorder(*cardlist1, CardList{"nobody here"}); // Trying to reorder a cardlist with an absent one does nothing exactly // since there's no other card to complete the operation @@ -316,7 +381,7 @@ TEST_CASE("Reordering Cardlists", "Board") { board.set_modified(false); SECTION("Reordering where sibling and next are already sibling and next") { - board.reorder_cardlist(*cardlist3, *cardlist2); + board.reorder(*cardlist3, *cardlist2); // Because cardlist3 is already next to cardlist2, nothing should be // done, therefore no modification whatsoeever @@ -329,7 +394,7 @@ TEST_CASE("Reordering Cardlists", "Board") { board.set_modified(false); SECTION("Reordering case 1") { - board.reorder_cardlist(*cardlist1, *cardlist3); + board.reorder(*cardlist1, *cardlist3); // Cardlist1 will be placed after cardlist 3, ths cardlist1 will be the // last element and a modification is registered @@ -342,7 +407,7 @@ TEST_CASE("Reordering Cardlists", "Board") { board.set_modified(false); SECTION("Reordering case 2") { - board.reorder_cardlist(*cardlist3, *cardlist1); + board.reorder(*cardlist3, *cardlist1); // Cardlist1 will be placed after cardlist 3, ths cardlist1 will be the // last element and a modification is registered @@ -361,8 +426,8 @@ TEST_CASE("Saving new boards") { CardList cardlist{"Things to do"}; Card card{"Computer Science", Color{123, 456, 123, 1}}; - cardlist.add_card(card); - board.add_cardlist(cardlist); + cardlist.add(card); + board.add(cardlist); board.save(); diff --git a/test/card-test.cpp b/test/card-test.cpp index 8f2bc08..a6e6c35 100644 --- a/test/card-test.cpp +++ b/test/card-test.cpp @@ -35,21 +35,21 @@ TEST_CASE("Card operations", "[Card]") { Task task2("Task2", true); Task task3("Task3"); - auto taskPtr1 = card.add_task(task1); - auto taskPtr2 = card.add_task(task2); - auto taskPtr3 = card.add_task(task3); + auto taskPtr1 = card.add(task1); + auto taskPtr2 = card.add(task2); + auto taskPtr3 = card.add(task3); - REQUIRE(!card.add_task(task1)); + REQUIRE(!card.add(task1)); REQUIRE(card.get_tasks().size() == 3); REQUIRE(*taskPtr1 == task1); REQUIRE(*taskPtr2 == task2); REQUIRE(*taskPtr3 == task3); - REQUIRE(card.remove_task(task2) == true); + REQUIRE(card.remove(task2) == true); REQUIRE(card.get_tasks().size() == 2); - REQUIRE(card.remove_task(task2) == + REQUIRE(card.remove(task2) == false); // Removing again should return false } @@ -57,8 +57,8 @@ TEST_CASE("Card operations", "[Card]") { Task task1("Task1", true); // Completed task Task task2("Task2", false); // Incomplete task - card.add_task(task1); - auto task2_sptr = card.add_task(task2); + card.add(task1); + auto task2_sptr = card.add(task2); double completion = card.get_completion(); REQUIRE(completion == @@ -70,7 +70,7 @@ TEST_CASE("Card operations", "[Card]") { 100.0); // Both tasks are now done, so 100% completion Task task3("Task3", false); // New incomplete task - card.add_task(task3); + card.add(task3); completion = card.get_completion(); REQUIRE(int(completion) == @@ -130,9 +130,9 @@ TEST_CASE("Task reordering", "[Card]") { Task task2{"MacOS"}; Task task3{"Debian"}; - card1.add_task(task1); - card1.add_task(task2); - card1.add_task(task3); + card1.add(task1); + card1.add(task2); + card1.add(task3); card1.set_modified(false); @@ -142,7 +142,7 @@ TEST_CASE("Task reordering", "[Card]") { REQUIRE(task2 == *card1_tasks[1]); REQUIRE(task3 == *card1_tasks[2]); - card1.reorder_task(task1, task3); // Moves "Windows" task after "Debian" + card1.reorder(task1, task3); // Moves "Windows" task after "Debian" CHECK(task1 == *card1_tasks[2]); CHECK(task2 == *card1_tasks[0]); diff --git a/test/cardlist-test.cpp b/test/cardlist-test.cpp index 437be13..040f5d9 100644 --- a/test/cardlist-test.cpp +++ b/test/cardlist-test.cpp @@ -9,7 +9,7 @@ TEST_CASE("CardList operations", "[CardList]") { SECTION("Add Card") { Card card1("Card1"); - auto addedCard1 = cardList.add_card(card1); + auto addedCard1 = cardList.add(card1); REQUIRE(addedCard1 != nullptr); REQUIRE(*addedCard1 == card1); @@ -20,12 +20,12 @@ TEST_CASE("CardList operations", "[CardList]") { SECTION("Remove Card") { Card card1("Card1"); Card card2("Card2"); - cardList.add_card(card1); - cardList.add_card(card2); + cardList.add(card1); + cardList.add(card2); - REQUIRE(cardList.remove_card(card1) == true); + REQUIRE(cardList.remove(card1) == true); REQUIRE(cardList.get_cards().size() == 1); - REQUIRE(cardList.remove_card(card1) == + REQUIRE(cardList.remove(card1) == false); // Removing the same card should return false REQUIRE(cardList.get_modified() == true); } @@ -35,15 +35,15 @@ TEST_CASE("CardList operations", "[CardList]") { Card card2("Card2"); Card card3("Card3"); - auto cardPtr1 = cardList.add_card(card1); - auto cardPtr2 = cardList.add_card(card2); - auto cardPtr3 = cardList.add_card(card3); + auto cardPtr1 = cardList.add(card1); + auto cardPtr2 = cardList.add(card2); + auto cardPtr3 = cardList.add(card3); REQUIRE(*cardList.get_cards().at(0) == card1); REQUIRE(*cardList.get_cards().at(1) == card2); REQUIRE(*cardList.get_cards().at(2) == card3); - cardList.reorder_card(card3, card1); // Move card3 after card1 + cardList.reorder(card3, card1); // Move card3 after card1 REQUIRE(*cardList.get_cards().at(0) == card1); REQUIRE(*cardList.get_cards().at(1) == card3); @@ -56,10 +56,10 @@ TEST_CASE("CardList operations", "[CardList]") { Card card1("Card1"); Card card2("Card2"); - auto cardPtr1 = cardList.add_card(card1); + auto cardPtr1 = cardList.add(card1); cardList.set_modified(false); - cardList.reorder_card(card1, card2); + cardList.reorder(card1, card2); REQUIRE(!cardList.get_modified()); } @@ -67,7 +67,7 @@ TEST_CASE("CardList operations", "[CardList]") { SECTION("Modified flag with internal card modification") { Card card1("Card1"); - auto cardPtr1 = cardList.add_card(card1); + auto cardPtr1 = cardList.add(card1); REQUIRE(cardList.get_modified() == true); cardList.get_modified(); // Reset the flag diff --git a/test/modification-test.cpp b/test/modification-test.cpp index b89cb8c..78f7f67 100644 --- a/test/modification-test.cpp +++ b/test/modification-test.cpp @@ -33,17 +33,17 @@ TEST_CASE("CardList add card marks modified", "[CardList]") { CardList cardlist("initial cardlist"); REQUIRE_FALSE(cardlist.get_modified()); Card card("initial card", NO_COLOR); - cardlist.add_card(card); + cardlist.add(card); REQUIRE(cardlist.get_modified()); } TEST_CASE("CardList remove card marks modified", "[CardList]") { CardList cardlist("initial cardlist"); Card card("initial card", NO_COLOR); - cardlist.add_card(card); + cardlist.add(card); cardlist.set_modified(false); REQUIRE_FALSE(cardlist.get_modified()); - cardlist.remove_card(card); + cardlist.remove(card); REQUIRE(cardlist.get_modified()); } @@ -51,18 +51,18 @@ TEST_CASE("CardList reorder cards marks modified", "[CardList]") { CardList cardlist("initial cardlist"); Card card1("card1", NO_COLOR); Card card2("card2", NO_COLOR); - cardlist.add_card(card1); - cardlist.add_card(card2); + cardlist.add(card1); + cardlist.add(card2); cardlist.set_modified(false); REQUIRE_FALSE(cardlist.get_modified()); - cardlist.reorder_card(card1, card2); + cardlist.reorder(card1, card2); REQUIRE(cardlist.get_modified()); } TEST_CASE("CardList modify card marks cardlist modified", "[CardList]") { CardList cardlist("initial cardlist"); Card card("initial card", NO_COLOR); - cardlist.add_card(card); + cardlist.add(card); cardlist.set_modified(false); REQUIRE_FALSE(cardlist.get_modified()); cardlist.get_cards().at(0)->set_name("new card name"); @@ -78,7 +78,7 @@ TEST_CASE("Card add task marks modified", "[Card]") { Card card("initial card", NO_COLOR); REQUIRE_FALSE(card.get_modified()); Task task("initial task"); - card.add_task(task); + card.add(task); REQUIRE(card.get_modified()); } @@ -99,7 +99,7 @@ TEST_CASE("Card set notes marks modified", "[Card]") { TEST_CASE("Card modify task marks card modified", "[Card]") { Card card("initial card", NO_COLOR); Task task("initial task"); - card.add_task(task); + card.add(task); card.set_modified(false); REQUIRE_FALSE(card.get_modified()); card.get_tasks().at(0)->set_done(true);