~aleteoryx/muditaos

981f9583aecb53fc50d75b0eaa689d1b1b1839fc — mkamonMdt 5 years ago ec26699
[EGD-4828] Add GUI tests for DOM flow

 * `DepthFirstItemTree` tests - basic traverse functionalities
 * `GuiVisitor` tests - basic double dispatch calls
 * DOM serializer tests - basic serialization functionalities
M module-gui/test/test-google/CMakeLists.txt => module-gui/test/test-google/CMakeLists.txt +5 -0
@@ 1,10 1,14 @@
project(googletest-gui)

include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
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-depthfirst-itemtree.cpp
        test-gui-visitor-call.cpp
        test-gui-dom-dump.cpp
        ../mock/TestListViewProvider.cpp
        )



@@ 20,6 24,7 @@ target_link_directories(${PROJECT_NAME} PUBLIC "${PROJECT_LIB_DIRECTORY}")
target_link_libraries(${PROJECT_NAME} PUBLIC module-utils module-gui)

target_link_libraries(${PROJECT_NAME} PUBLIC gtest gtest_main)
target_link_libraries(${PROJECT_NAME} PUBLIC gmock gmock_main)

add_test(NAME ${PROJECT_NAME}
        COMMAND ${PROJECT_NAME}

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

#include "gtest/gtest.h"

#include "visitor/DepthFirstItemTree.hpp"
#include "Item.hpp"

#include <vector>
#include <iostream>

class DepthFirstTreeTesting : public ::testing::Test
{

    gui::Item root;
    std::vector<gui::Item *> firstLevelChildren;
    std::vector<gui::Item *> secondLevelChildren;

    void addItem(gui::Item *parent, std::vector<gui::Item *> &childrenList)
    {
        auto item = new gui::Item();
        parent->addWidget(item);
        childrenList.push_back(item);
    }

  protected:
    DepthFirstTreeTesting(gui::DepthFirstItemTree::TraverseMode mode)
    {
        // adding 1st-level children to root
        addItem(&root, firstLevelChildren);
        addItem(&root, firstLevelChildren);
        addItem(&root, firstLevelChildren);

        // adding 2nd-level children
        auto child = firstLevelChildren.back();
        addItem(child, secondLevelChildren);
        addItem(child, secondLevelChildren);
        addItem(child, secondLevelChildren);
        child = firstLevelChildren.front();
        addItem(child, secondLevelChildren);
        addItem(child, secondLevelChildren);
        addItem(child, secondLevelChildren);

        tree = std::make_unique<gui::DepthFirstItemTree>(root, mode);
    }

  public:
    static constexpr auto rootLevel   = 0;
    static constexpr auto firstLevel  = 1;
    static constexpr auto secondLevel = 2;

    std::unique_ptr<gui::DepthFirstItemTree> tree;

    gui::Item *getRoot()
    {
        return &root;
    }
    const std::vector<gui::Item *> &get1stLevelChildren() const
    {
        return firstLevelChildren;
    }
    const std::vector<gui::Item *> &get2ndtLevelChildren() const
    {
        return secondLevelChildren;
    }
};

class DFTPreOrderTesting : public DepthFirstTreeTesting
{
  protected:
    DFTPreOrderTesting() : DepthFirstTreeTesting(gui::DepthFirstItemTree::TraverseMode::PreOrder)
    {}
};

class DFTPostOrderTesting : public DepthFirstTreeTesting
{

  protected:
    DFTPostOrderTesting() : DepthFirstTreeTesting(gui::DepthFirstItemTree::TraverseMode::PostOrder)
    {}
};

TEST_F(DFTPreOrderTesting, RootAtFrontTest)
{
    ASSERT_TRUE(tree->hasNext());
    auto node = tree->getNext();
    ASSERT_EQ(node.getLevel(), rootLevel);
    ASSERT_EQ(&node.getItem(), getRoot());
}

TEST_F(DFTPreOrderTesting, SecondLevelChildAtEndTest)
{
    ASSERT_TRUE(tree->hasNext());
    while (tree->hasNext()) {
        auto node = tree->getNext();
        if (!tree->hasNext()) {
            ASSERT_EQ(node.getLevel(), secondLevel);
        }
    }
}

TEST_F(DFTPreOrderTesting, ExpectedNodesCountTest)
{
    const int expectedCount = 1 + get1stLevelChildren().size() + get2ndtLevelChildren().size();
    int currentCount        = 0;
    while (tree->hasNext()) {
        auto node = tree->getNext();
        EXPECT_GT(node.getLevel(), -1);
        currentCount++;
    }
    ASSERT_EQ(expectedCount, currentCount);
}

TEST_F(DFTPreOrderTesting, ExpectedLevelOrderTest)
{
    ASSERT_TRUE(tree->hasNext());
    std::list<int> expectedLevelOrder = {0, 1, 2, 2, 2, 1, 1, 2, 2, 2};

    while (tree->hasNext()) {
        ASSERT_GT(expectedLevelOrder.size(), 0);
        auto node = tree->getNext();
        EXPECT_EQ(node.getLevel(), expectedLevelOrder.front());
        expectedLevelOrder.pop_front();
    }
    ASSERT_EQ(expectedLevelOrder.size(), 0);
}

TEST_F(DFTPostOrderTesting, RootAtEndTest)
{
    ASSERT_TRUE(tree->hasNext());
    while (tree->hasNext()) {
        auto node = tree->getNext();
        if (!tree->hasNext()) {
            ASSERT_EQ(node.getLevel(), rootLevel);
            ASSERT_EQ(&node.getItem(), getRoot());
        }
    }
}

TEST_F(DFTPostOrderTesting, SecondLevelChildAtFrontTest)
{
    ASSERT_TRUE(tree->hasNext());
    auto node = tree->getNext();
    ASSERT_EQ(node.getLevel(), secondLevel);
}

TEST_F(DFTPostOrderTesting, ExpectedNodesCountTest)
{
    const int expectedCount = 1 + get1stLevelChildren().size() + get2ndtLevelChildren().size();
    int currentCount        = 0;
    while (tree->hasNext()) {
        auto node = tree->getNext();
        EXPECT_GT(node.getLevel(), -1);
        currentCount++;
    }
    ASSERT_EQ(expectedCount, currentCount);
}

TEST_F(DFTPostOrderTesting, ExpectedLevelOrderTest)
{
    ASSERT_TRUE(tree->hasNext());
    std::list<int> expectedLevelOrder = {2, 2, 2, 1, 1, 2, 2, 2, 1, 0};

    while (tree->hasNext()) {
        ASSERT_GT(expectedLevelOrder.size(), 0);
        auto node = tree->getNext();
        EXPECT_EQ(node.getLevel(), expectedLevelOrder.front());
        expectedLevelOrder.pop_front();
    }
    ASSERT_EQ(expectedLevelOrder.size(), 0);
}

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

#include "gtest/gtest.h"
#include <sstream>

#include "gui/dom/Item2JsonSerializer.hpp"

#include "Item.hpp"
#include "Rect.hpp"
#include "Label.hpp"
#include "Text.hpp"
#include "FontManager.hpp"
#include <iostream>

class Item2JsonSerializerTester : public ::testing::Test
{
  protected:
    static constexpr auto testTextValue1 = "Some text 1";
    static constexpr auto testTextValue2 = "Some text 2";
    Item2JsonSerializerTester()
    {
        auto &fm = gui::FontManager::getInstance();
        fm.init("assets");

        root.addWidget(new gui::Text(nullptr, 0, 0, 0, 0, testTextValue1));
        root.addWidget(new gui::Label(nullptr, 0, 0, 0, 0, testTextValue2));

        serializer.traverse(root);
        std::stringstream ss;
        serializer.dump(ss);
        serializedItem = ss.str();
    }
    gui::Item2JsonSerializer serializer;

  public:
    gui::Item root;
    std::string serializedItem;
};

TEST_F(Item2JsonSerializerTester, ChildrenCountTest)
{
    constexpr auto expectedRootChildrenCountPhrase  = "\"ChildrenCount\": 2";
    constexpr auto expectedChildChildrenCountPhrase = "\"ChildrenCount\": 0";

    const auto rootPhrasePos = serializedItem.find(expectedRootChildrenCountPhrase);
    ASSERT_NE(rootPhrasePos, std::string::npos);

    const auto firstChildPhrasePos = serializedItem.find(expectedChildChildrenCountPhrase);
    ASSERT_NE(rootPhrasePos, std::string::npos);

    const auto secondChildPhrasePos = serializedItem.find(expectedChildChildrenCountPhrase, firstChildPhrasePos);
    ASSERT_NE(secondChildPhrasePos, std::string::npos);
}

TEST_F(Item2JsonSerializerTester, TextValueTest)
{
    ASSERT_NE(serializedItem.find(testTextValue1), std::string::npos);
    ASSERT_NE(serializedItem.find(testTextValue2), std::string::npos);
}

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

#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include "visitor/GuiVisitor.hpp"
#include "Text.hpp"
#include "Item.hpp"
#include "Rect.hpp"
#include "Label.hpp"
#include "Window.hpp"
#include "BottomBar.hpp"
#include "TopBar.hpp"

using ::testing::Matcher;
using ::testing::Ref;

class VisitorMock : public gui::GuiVisitor
{
  public:
    MOCK_METHOD1(visit, void(gui::Item &item));
    MOCK_METHOD1(visit, void(gui::Rect &item));
    MOCK_METHOD1(visit, void(gui::Text &item));
    MOCK_METHOD1(visit, void(gui::Window &item));
    MOCK_METHOD1(visit, void(gui::Label &item));
    MOCK_METHOD1(visit, void(gui::BottomBar &item));
    MOCK_METHOD1(visit, void(gui::TopBar &item));
};

class CustomRect : public gui::Rect
{};

struct VisitAcceptors : public ::testing::Test
{
    gui::Item item;
    gui::Rect rect;

    gui::Text text;
    CustomRect customRect;
};

TEST_F(VisitAcceptors, VisitCallOnItem)
{
    auto &testSubject = item;
    VisitorMock visitor;
    EXPECT_CALL(visitor, visit(Matcher<gui::Item &>(Ref(testSubject)))).Times(1);
    testSubject.accept(visitor);
}

TEST_F(VisitAcceptors, VisitCallOnRect)
{
    auto &testSubject = rect;
    VisitorMock visitor;
    EXPECT_CALL(visitor, visit(Matcher<gui::Item &>(Ref(testSubject)))).Times(0);
    EXPECT_CALL(visitor, visit(Matcher<gui::Rect &>(Ref(testSubject)))).Times(1);
    testSubject.accept(visitor);
}

TEST_F(VisitAcceptors, VisitCallOnText)
{
    auto &testSubject = text;
    VisitorMock visitor;
    EXPECT_CALL(visitor, visit(Matcher<gui::Item &>(Ref(testSubject)))).Times(0);
    EXPECT_CALL(visitor, visit(Matcher<gui::Rect &>(Ref(testSubject)))).Times(0);
    EXPECT_CALL(visitor, visit(Matcher<gui::Text &>(Ref(testSubject)))).Times(1);
    testSubject.accept(visitor);
}

TEST_F(VisitAcceptors, VisitCallOnCustomRect)
{
    auto &testSubject = customRect;
    VisitorMock visitor;
    EXPECT_CALL(visitor, visit(Matcher<gui::Item &>(Ref(testSubject)))).Times(0);
    EXPECT_CALL(visitor, visit(Matcher<gui::Rect &>(Ref(testSubject)))).Times(1);
    testSubject.accept(visitor);
}