~aleteoryx/muditaos

271490075817fe8096a5e54ce34357cc11c14ec9 — Tomasz Langowski 5 years ago 1238684
[EGD-5141] Add unit tests for grid layout

Unit tests for grid layout added (one test for borderCallback
behavior).
M module-gui/gui/widgets/GridLayout.cpp => module-gui/gui/widgets/GridLayout.cpp +12 -0
@@ 69,6 69,16 @@ uint32_t GridLayout::calculateRowSizeForBorderTransition(const uint32_t currentP
    return realRowSize;
}

void GridLayout::handleItemsOutOfGridLayoutArea(uint32_t maxItemsInArea)
{
    for (auto i = maxItemsInArea; i < children.size(); i++) {
        auto it = std::next(children.begin(), i);
        if ((*it)->visible) {
            addToOutOfDrawAreaList(*it);
        }
    }
}

void GridLayout::resizeItems()
{
    if (grid.x == 0 || grid.y == 0) {


@@ 78,6 88,7 @@ void GridLayout::resizeItems()
    uint32_t el_in_x = area().w / grid.x;
    uint32_t el_in_y = area().h / grid.y;

    elementsInIncompletedLastRow = 0;
    colSize = children.size() < area().w / grid.x ? children.size() : area().w / grid.x;
    rowSize = colSize != 0 ? (children.size() / colSize) : 1;
    if (colSize > 1 && (static_cast<double>(children.size()) / colSize) > 1.0) {


@@ 99,6 110,7 @@ void GridLayout::resizeItems()
        LOG_ERROR("More children than possible to show: %u > %" PRIu32 "",
                  static_cast<unsigned int>(children.size()),
                  max_elements);
        handleItemsOutOfGridLayoutArea(max_elements);
        return;
    }
    if (el_in_x > 2)

M module-gui/gui/widgets/GridLayout.hpp => module-gui/gui/widgets/GridLayout.hpp +2 -0
@@ 41,6 41,8 @@ namespace gui
      private:
        uint32_t calculateColumnSizeForBorderTransition(const uint32_t currentPosition);
        uint32_t calculateRowSizeForBorderTransition(const uint32_t currentPosition);

        void handleItemsOutOfGridLayoutArea(uint32_t maxItemsInArea);
    };

}; // namespace gui

M module-gui/test/test-google/CMakeLists.txt => module-gui/test/test-google/CMakeLists.txt +1 -0
@@ 6,6 6,7 @@ include_directories(${gmock_SOURCE_DIR}/include ${gmock_SOURCE_DIR})
add_executable(${PROJECT_NAME} EXCLUDE_FROM_ALL
        test-gui-listview.cpp
        test-gui-boxlayout.cpp
        test-gui-gridlayout.cpp
        test-gui-depthfirst-itemtree.cpp
        test-gui-visitor-call.cpp
        test-gui-dom-dump.cpp

A module-gui/test/test-google/test-gui-gridlayout.cpp => module-gui/test/test-google/test-gui-gridlayout.cpp +248 -0
@@ 0,0 1,248 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "gtest/gtest.h"
#include <module-utils/log/log.hpp>
#include <module-gui/gui/widgets/BoxLayout.hpp>
#include <module-gui/gui/widgets/GridLayout.hpp>
#include <gui/input/InputEvent.hpp>

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);
        }
    }

    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<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
    moveNTimes(gridLayout, 2, gui::KeyCode::KEY_RIGHT);
    ASSERT_EQ(3, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 3 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(3 + expColSize, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 3 + expColSize << " should have focus";
    moveNTimes(gridLayout, 2, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(1 + expColSize, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 + expColSize << " should have focus";
}
///> TODO: Enable this test when issue with setFocus will be resolved
TEST_F(GridLayoutTesting, DISABLED_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<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP);
    ASSERT_EQ(37, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 37 << " should have focus";
    moveNTimes(gridLayout, 9, gui::KeyCode::KEY_RIGHT);
    ASSERT_EQ(46, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 46 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_RIGHT);
    ASSERT_EQ(37, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 37 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(46, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 37 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(10, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 10 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_RIGHT);
    ASSERT_EQ(11, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 11 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP);
    ASSERT_EQ(35, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 35 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(11, dynamic_cast<TestItem *>(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<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP);
    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_RIGHT);
    ASSERT_EQ(1, dynamic_cast<TestItem *>(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<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP);
    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(1, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 1 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_LEFT);
    ASSERT_EQ(2, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 2 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_UP);
    ASSERT_EQ(2, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 2 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_DOWN);
    ASSERT_EQ(2, dynamic_cast<TestItem *>(gridLayout->getFocusItem())->ID)
        << "element with ID " << 2 << " should have focus";
    moveNTimes(gridLayout, 1, gui::KeyCode::KEY_RIGHT);
    ASSERT_EQ(1, dynamic_cast<TestItem *>(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<TestItem *>(item)->ID - 1) % expColSize;
        auto currRow    = (dynamic_cast<TestItem *>(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<TestItem *>(item)->ID << " is invalid";
        ASSERT_EQ(item->getPosition(gui::Axis::X), currPos_X)
            << "X coordinate value for " << dynamic_cast<TestItem *>(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);
}