// Copyright (c) 2017-2023, Mudita Sp. z.o.o. All rights reserved. // For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md #include "gtest/gtest.h" #include #include #include #include namespace testStyle { const inline uint32_t box_x = 0; const inline uint32_t box_y = 0; const inline uint32_t box_w = 600; const inline uint32_t box_h = 200; const inline uint32_t grid_item_w = 50; const inline uint32_t grid_item_h = 50; } // namespace testStyle class TestItem : public gui::Rect { public: unsigned int ID = 0; TestItem(Item *parent, uint32_t x, uint32_t y, uint32_t w, uint32_t h) : Rect(parent, x, y, w, h){}; }; class GridLayoutTesting : public ::testing::Test { protected: void SetUp() override { gridLayout = new gui::GridLayout(testStyle::box_x, testStyle::box_y, testStyle::box_w, testStyle::box_h, {testStyle::grid_item_w, testStyle::grid_item_h}); ASSERT_EQ(0, gridLayout->children.size()) << "GridLayout should be empty"; } void TearDown() override { delete gridLayout; } void moveNTimes(gui::BoxLayout *Box, unsigned int n, gui::KeyCode key) { for (unsigned int i = 0; i < n; i++) { Box->onInput(gui::InputEvent({}, gui::InputEvent::State::keyReleasedShort, key)); } } void addNItems(gui::BoxLayout *Box, unsigned int n, uint32_t item_w, uint32_t item_h, const gui::Margins &margins = gui::Margins()) { for (unsigned int i = 1; i <= n; i++) { auto item = new TestItem(nullptr, 0, 0, item_w, item_h); item->ID = i; item->visible = true; item->setMargins(margins); Box->addWidget(item); } } void addItem(gui::BoxLayout *Box, uint32_t item_w, uint32_t item_h, uint32_t id, bool active = true, const gui::Margins &margins = gui::Margins()) { auto item = new TestItem(nullptr, 0, 0, item_w, item_h); item->ID = id; item->visible = true; item->setMargins(margins); item->activeItem = active; Box->addWidget(item); } gui::GridLayout *gridLayout = nullptr; ///> GridLayout test constants const uint32_t expRowSize = testStyle::box_h / testStyle::grid_item_h; const uint32_t expColSize = testStyle::box_w / testStyle::grid_item_w; const uint32_t allElementsCount = expRowSize * expColSize; }; TEST_F(GridLayoutTesting, Constructor_Destructor_Test) { // Check that there are no memory leaks - done by fixture setup and teardown. } TEST_F(GridLayoutTesting, Fill_GridLayout_Test) { for (uint32_t i = 0; i < allElementsCount; i++) { addNItems(gridLayout, 1, testStyle::grid_item_w, testStyle::grid_item_h); ASSERT_EQ(i + 1, gridLayout->children.size()) << "GridLayout should contain " << i << " elements"; ASSERT_TRUE(gridLayout->children.back()->visible) << "Last element should be visible"; } addNItems(gridLayout, 1, testStyle::grid_item_w, testStyle::grid_item_h); ASSERT_EQ(allElementsCount + 1, gridLayout->children.size()) << "GridLayout should contain " << allElementsCount + 1 << " elements"; ASSERT_FALSE(gridLayout->children.back()->visible) << "Last element shouldn't be visible"; } TEST_F(GridLayoutTesting, Navigate_Test) { ///> Test for grid layout with 48 elements ///> | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | ///> | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ///> | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | ///> | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | addNItems(gridLayout, allElementsCount, testStyle::grid_item_w, testStyle::grid_item_h); gridLayout->setFocus(true); ASSERT_EQ(gridLayout->rowSize, 4) << "row size is not " << 4 << " as expected"; ASSERT_EQ(gridLayout->colSize, 12) << "col size is not " << 12 << " as expected"; ASSERT_EQ(allElementsCount, gridLayout->children.size()) << "GridLayout should contain " << allElementsCount << " elements"; ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; moveNTimes(gridLayout, 2, gui::KeyCode::KEY_RIGHT); ASSERT_EQ(3, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 3 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN); ASSERT_EQ(3 + expColSize, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 3 + expColSize << " should have focus"; moveNTimes(gridLayout, 2, gui::KeyCode::KEY_LEFT); ASSERT_EQ(1 + expColSize, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 + expColSize << " should have focus"; } TEST_F(GridLayoutTesting, Navigate_Test_ActiveItems_1) { ///> Test for grid layout with 48 elements (A - active item, N - non active item, NV - non visible item) ///> | 1 A | 2 NA | 3 A | 4 NA | 5 A | 6 NA | 7 A | 8 NA | 9 A | 10 NA | 11 A | 12 NA | ///> | 13 NA | 14 A | 15 NA | 16 A | 17 NA | 18 A | 19 NA | 20 A | 21 NA | 22 A | 23 NA | 24 A | ///> | 25 A | 26 NA | 27 A | 28 NA | 29 A | 30 NA | 31 A | 32 NA | 33 A | 34 NA | 35 A | 36 NA | ///> | 37 NA | 38 A | 39 NA | 40 A | 41 NA | 42 A | 43 NA | 44 A | 45 NA | 46 A | 47 NA | 48 A | ///> | 49 NV | 50 NV | 51 NV | 52 NV | for (uint32_t i = 1; i <= 12; i++) { addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, (i % 2) ? true : false); } for (uint32_t i = 13; i <= 24; i++) { addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, ((i + 1) % 2) ? true : false); } for (uint32_t i = 25; i <= 36; i++) { addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, (i % 2) ? true : false); } for (uint32_t i = 37; i <= 48; i++) { addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, ((i + 1) % 2) ? true : false); } ///> Add some items to exceed grid layout area for (uint32_t i = 49; i <= 52; i++) { addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, true); } gridLayout->setFocus(true); ASSERT_EQ(gridLayout->rowSize, 4) << "row size is not " << 4 << " as expected"; ASSERT_EQ(gridLayout->colSize, 12) << "col size is not " << 12 << " as expected"; ASSERT_EQ(52, gridLayout->children.size()) << "GridLayout should contain " << 52 << " elements"; ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; moveNTimes(gridLayout, 2, gui::KeyCode::KEY_RIGHT); ASSERT_EQ(5, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 5 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN); ASSERT_EQ(5 + (2 * expColSize), dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 5 + (2 * expColSize) << " should have focus"; moveNTimes(gridLayout, 2, gui::KeyCode::KEY_LEFT); ASSERT_EQ(1 + (2 * expColSize), dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 + (2 * expColSize) << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN); ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; } TEST_F(GridLayoutTesting, Navigate_Test_ActiveItems_2_BorderCallback) { ///> Test for grid layout with 48 elements ///> | 1 A | 2 NA | 3 A | 4 NA | 5 A | 6 NA | 7 A | 8 NA | 9 A | 10 NA | 11 A | 12 NA | ///> | 13 NA | 14 A | 15 NA | 16 A | 17 NA | 18 A | 19 NA | 20 A | 21 NA | 22 A | 23 NA | 24 A | ///> | 25 A | 26 NA | 27 A | 28 NA | 29 A | 30 NA | 31 A | 32 NA | 33 A | 34 NA | 35 A | 36 NA | ///> | 37 NA | 38 A | 39 NA | for (uint32_t i = 1; i <= 12; i++) { addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, (i % 2) ? true : false); } for (uint32_t i = 13; i <= 24; i++) { addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, ((i + 1) % 2) ? true : false); } for (uint32_t i = 25; i <= 36; i++) { addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, (i % 2) ? true : false); } for (uint32_t i = 37; i <= 39; i++) { addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, i, ((i + 1) % 2) ? true : false); } gridLayout->setFocus(true); ASSERT_EQ(gridLayout->rowSize, 4) << "row size is not " << 4 << " as expected"; ASSERT_EQ(gridLayout->colSize, 12) << "col size is not " << 12 << " as expected"; ASSERT_EQ(39, gridLayout->children.size()) << "GridLayout should contain " << 39 << " elements"; ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; moveNTimes(gridLayout, 2, gui::KeyCode::KEY_LEFT); ASSERT_EQ(9, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 9 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP); ASSERT_EQ(33, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 33 << " should have focus"; moveNTimes(gridLayout, 3, gui::KeyCode::KEY_LEFT); ASSERT_EQ(27, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 27 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN); ASSERT_EQ(3, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 3 << " should have focus"; moveNTimes(gridLayout, 5, gui::KeyCode::KEY_RIGHT); ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; ///> Test for grid layout with 1 element ///> | 1NA | gridLayout->erase(); addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, 1, false); ASSERT_EQ(gridLayout->children.size(), 1) << "elements size is not " << 1 << " as expected"; ASSERT_EQ(gridLayout->rowSize, 1) << "row size is not " << 1 << " as expected"; ASSERT_EQ(gridLayout->colSize, 1) << "col size is not " << 1 << " as expected"; gridLayout->setFocus(false); gridLayout->setFocus(true); ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_LEFT); ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_RIGHT); ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP); ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN); ASSERT_EQ(nullptr, gridLayout->getFocusItem()) << "no element shall be focused"; ///> Test for grid layout with 1 element ///> | 1NA | 1A | gridLayout->erase(); addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, 1, false); addItem(gridLayout, testStyle::grid_item_w, testStyle::grid_item_h, 2, true); ASSERT_EQ(gridLayout->children.size(), 2) << "elements size is not " << 2 << " as expected"; ASSERT_EQ(gridLayout->rowSize, 1) << "row size is not " << 1 << " as expected"; ASSERT_EQ(gridLayout->colSize, 2) << "col size is not " << 2 << " as expected"; gridLayout->setFocus(false); gridLayout->setFocus(true); ASSERT_EQ(2, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 2 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_LEFT); ASSERT_EQ(2, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 2 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_RIGHT); ASSERT_EQ(2, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 2 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP); ASSERT_EQ(2, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 2 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN); ASSERT_EQ(2, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 2 << " should have focus"; } ///> TODO: Enable this test when issue with setFocus will be resolved TEST_F(GridLayoutTesting, Border_Callback_Test) { ///> Test for grid layout with 46 elements ///> | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | ///> | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ///> | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | ///> | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | addNItems(gridLayout, allElementsCount - 2, testStyle::grid_item_w, testStyle::grid_item_h); gridLayout->setFocus(true); ASSERT_EQ(gridLayout->rowSize, 4) << "row size is not " << 4 << " as expected"; ASSERT_EQ(gridLayout->colSize, 12) << "col size is not " << 12 << " as expected"; ASSERT_EQ(allElementsCount - 2, gridLayout->children.size()) << "GridLayout should contain " << allElementsCount - 2 << " elements"; ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP); ASSERT_EQ(37, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 37 << " should have focus"; moveNTimes(gridLayout, 9, gui::KeyCode::KEY_RIGHT); ASSERT_EQ(46, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 46 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_RIGHT); ASSERT_EQ(37, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 37 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_LEFT); ASSERT_EQ(46, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 46 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN); ASSERT_EQ(10, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 10 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_RIGHT); ASSERT_EQ(11, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 11 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP); ASSERT_EQ(35, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 35 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN); ASSERT_EQ(11, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 11 << " should have focus"; ///> Test for grid layout with 1 element ///> | 1 | gridLayout->erase(); addNItems(gridLayout, 1, testStyle::grid_item_w, testStyle::grid_item_h); ASSERT_EQ(gridLayout->children.size(), 1) << "elements size is not " << 1 << " as expected"; ASSERT_EQ(gridLayout->rowSize, 1) << "row size is not " << 1 << " as expected"; ASSERT_EQ(gridLayout->colSize, 1) << "col size is not " << 1 << " as expected"; gridLayout->setFocus(true); ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP); ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN); ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_LEFT); ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_RIGHT); ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; ///> Test for grid layout with 2 elements ///> | 1 | 2 | gridLayout->erase(); addNItems(gridLayout, 2, testStyle::grid_item_w, testStyle::grid_item_h); ASSERT_EQ(gridLayout->children.size(), 2) << "elements size is not " << 2 << " as expected"; ASSERT_EQ(gridLayout->rowSize, 1) << "row size is not " << 1 << " as expected"; ASSERT_EQ(gridLayout->colSize, 2) << "col size is not " << 2 << " as expected"; gridLayout->setFocus(true); ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP); ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN); ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_LEFT); ASSERT_EQ(2, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 2 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP); ASSERT_EQ(2, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 2 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN); ASSERT_EQ(2, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 2 << " should have focus"; moveNTimes(gridLayout, 1, gui::KeyCode::KEY_RIGHT); ASSERT_EQ(1, dynamic_cast(gridLayout->getFocusItem())->ID) << "element with ID " << 1 << " should have focus"; } TEST_F(GridLayoutTesting, Items_Position_Test) { ///> Test for grid layout with 48 elements ///> | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | ///> | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ///> | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | ///> | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | addNItems(gridLayout, allElementsCount, testStyle::grid_item_w, testStyle::grid_item_h); ASSERT_EQ(allElementsCount, gridLayout->children.size()) << "GridLayout should contain 48 elements"; for (auto item : gridLayout->children) { auto currColumn = (dynamic_cast(item)->ID - 1) % expColSize; auto currRow = (dynamic_cast(item)->ID - 1) / expColSize; auto currPos_X = currColumn * testStyle::grid_item_w; auto currPos_Y = currRow * testStyle::grid_item_h; ASSERT_EQ(item->getPosition(gui::Axis::Y), currPos_Y) << "Y coordinate value for " << dynamic_cast(item)->ID << " is invalid"; ASSERT_EQ(item->getPosition(gui::Axis::X), currPos_X) << "X coordinate value for " << dynamic_cast(item)->ID << " is invalid"; } gridLayout->erase(); addNItems(gridLayout, allElementsCount + 1, testStyle::grid_item_w, testStyle::grid_item_h); ASSERT_EQ(allElementsCount + 1, gridLayout->children.size()) << "GridLayout should contain 49 elements"; ///> Make sure that not visible elements has not been moved ASSERT_EQ((*gridLayout->children.rbegin())->getPosition(gui::Axis::Y), 0); ASSERT_EQ((*gridLayout->children.rbegin())->getPosition(gui::Axis::X), 0); }