Add some tests for NotebookTab (#5070)

* EmptyApplication: Add asserts to rest of getters (except for getSeventvAPI)

* Theme: make getTheme call getIApp()->getThemes() instead

this allows it to be used in tests
realistically this should be deprecated & users of it should just call
getIApp()->getThemes() directly

* Use getIApp() instead of getApp() in a few places
This commit is contained in:
pajlada
2024-01-06 11:42:45 +01:00
committed by GitHub
parent 77eb9cc1e9
commit 99b537ffd9
8 changed files with 193 additions and 13 deletions
+39
View File
@@ -17,61 +17,90 @@ public:
Theme *getThemes() override Theme *getThemes() override
{ {
assert(
false &&
"EmptyApplication::getThemes was called without being initialized");
return nullptr; return nullptr;
} }
Fonts *getFonts() override Fonts *getFonts() override
{ {
assert(
false &&
"EmptyApplication::getFonts was called without being initialized");
return nullptr; return nullptr;
} }
IEmotes *getEmotes() override IEmotes *getEmotes() override
{ {
assert(
false &&
"EmptyApplication::getEmotes was called without being initialized");
return nullptr; return nullptr;
} }
AccountController *getAccounts() override AccountController *getAccounts() override
{ {
assert(false && "EmptyApplication::getAccounts was called without "
"being initialized");
return nullptr; return nullptr;
} }
HotkeyController *getHotkeys() override HotkeyController *getHotkeys() override
{ {
assert(false && "EmptyApplication::getHotkeys was called without being "
"initialized");
return nullptr; return nullptr;
} }
WindowManager *getWindows() override WindowManager *getWindows() override
{ {
assert(false && "EmptyApplication::getWindows was called without being "
"initialized");
return nullptr; return nullptr;
} }
Toasts *getToasts() override Toasts *getToasts() override
{ {
assert(
false &&
"EmptyApplication::getToasts was called without being initialized");
return nullptr; return nullptr;
} }
CrashHandler *getCrashHandler() override CrashHandler *getCrashHandler() override
{ {
assert(false && "EmptyApplication::getCrashHandler was called without "
"being initialized");
return nullptr; return nullptr;
} }
CommandController *getCommands() override CommandController *getCommands() override
{ {
assert(false && "EmptyApplication::getCommands was called without "
"being initialized");
return nullptr; return nullptr;
} }
NotificationController *getNotifications() override NotificationController *getNotifications() override
{ {
assert(false && "EmptyApplication::getNotifications was called without "
"being initialized");
return nullptr; return nullptr;
} }
HighlightController *getHighlights() override HighlightController *getHighlights() override
{ {
assert(false && "EmptyApplication::getHighlights was called without "
"being initialized");
return nullptr; return nullptr;
} }
ITwitchIrcServer *getTwitch() override ITwitchIrcServer *getTwitch() override
{ {
assert(
false &&
"EmptyApplication::getTwitch was called without being initialized");
return nullptr; return nullptr;
} }
@@ -83,11 +112,15 @@ public:
ChatterinoBadges *getChatterinoBadges() override ChatterinoBadges *getChatterinoBadges() override
{ {
assert(false && "EmptyApplication::getChatterinoBadges was called "
"without being initialized");
return nullptr; return nullptr;
} }
FfzBadges *getFfzBadges() override FfzBadges *getFfzBadges() override
{ {
assert(false && "EmptyApplication::getFfzBadges was called without "
"being initialized");
return nullptr; return nullptr;
} }
@@ -99,6 +132,8 @@ public:
IUserDataController *getUserData() override IUserDataController *getUserData() override
{ {
assert(false && "EmptyApplication::getUserData was called without "
"being initialized");
return nullptr; return nullptr;
} }
@@ -110,11 +145,15 @@ public:
ITwitchLiveController *getTwitchLiveController() override ITwitchLiveController *getTwitchLiveController() override
{ {
assert(false && "EmptyApplication::getTwitchLiveController was called "
"without being initialized");
return nullptr; return nullptr;
} }
ImageUploader *getImageUploader() override ImageUploader *getImageUploader() override
{ {
assert(false && "EmptyApplication::getImageUploader was called without "
"being initialized");
return nullptr; return nullptr;
} }
+1 -1
View File
@@ -476,7 +476,7 @@ void Theme::normalizeColor(QColor &color) const
Theme *getTheme() Theme *getTheme()
{ {
return getApp()->themes; return getIApp()->getThemes();
} }
} // namespace chatterino } // namespace chatterino
+2 -3
View File
@@ -1,5 +1,6 @@
#include "widgets/BaseWidget.hpp" #include "widgets/BaseWidget.hpp"
#include "Application.hpp"
#include "common/QLogging.hpp" #include "common/QLogging.hpp"
#include "controllers/hotkeys/HotkeyController.hpp" #include "controllers/hotkeys/HotkeyController.hpp"
#include "singletons/Theme.hpp" #include "singletons/Theme.hpp"
@@ -17,10 +18,8 @@ namespace chatterino {
BaseWidget::BaseWidget(QWidget *parent, Qt::WindowFlags f) BaseWidget::BaseWidget(QWidget *parent, Qt::WindowFlags f)
: QWidget(parent, f) : QWidget(parent, f)
, theme(getIApp()->getThemes())
{ {
// REMOVED
this->theme = getTheme();
this->signalHolder_.managedConnect(this->theme->updated, [this]() { this->signalHolder_.managedConnect(this->theme->updated, [this]() {
this->themeChangedEvent(); this->themeChangedEvent();
+6 -4
View File
@@ -588,11 +588,13 @@ void Notebook::updateTabVisibility()
void Notebook::updateTabVisibilityMenuAction() void Notebook::updateTabVisibilityMenuAction()
{ {
auto toggleSeq = getApp()->hotkeys->getDisplaySequence( const auto *hotkeys = getIApp()->getHotkeys();
auto toggleSeq = hotkeys->getDisplaySequence(
HotkeyCategory::Window, "setTabVisibility", {std::vector<QString>()}); HotkeyCategory::Window, "setTabVisibility", {std::vector<QString>()});
if (toggleSeq.isEmpty()) if (toggleSeq.isEmpty())
{ {
toggleSeq = getApp()->hotkeys->getDisplaySequence( toggleSeq = hotkeys->getDisplaySequence(
HotkeyCategory::Window, "setTabVisibility", {{"toggle"}}); HotkeyCategory::Window, "setTabVisibility", {{"toggle"}});
} }
@@ -601,12 +603,12 @@ void Notebook::updateTabVisibilityMenuAction()
// show contextual shortcuts // show contextual shortcuts
if (this->getShowTabs()) if (this->getShowTabs())
{ {
toggleSeq = getApp()->hotkeys->getDisplaySequence( toggleSeq = hotkeys->getDisplaySequence(
HotkeyCategory::Window, "setTabVisibility", {{"off"}}); HotkeyCategory::Window, "setTabVisibility", {{"off"}});
} }
else if (!this->getShowTabs()) else if (!this->getShowTabs())
{ {
toggleSeq = getApp()->hotkeys->getDisplaySequence( toggleSeq = hotkeys->getDisplaySequence(
HotkeyCategory::Window, "setTabVisibility", {{"on"}}); HotkeyCategory::Window, "setTabVisibility", {{"on"}});
} }
} }
+15 -5
View File
@@ -93,8 +93,8 @@ NotebookTab::NotebookTab(Notebook *notebook)
[this]() { [this]() {
this->notebook_->removePage(this->page); this->notebook_->removePage(this->page);
}, },
getApp()->hotkeys->getDisplaySequence(HotkeyCategory::Window, getIApp()->getHotkeys()->getDisplaySequence(HotkeyCategory::Window,
"removeTab")); "removeTab"));
this->menu_.addAction( this->menu_.addAction(
"Popup Tab", "Popup Tab",
@@ -104,8 +104,8 @@ NotebookTab::NotebookTab(Notebook *notebook)
container->popup(); container->popup();
} }
}, },
getApp()->hotkeys->getDisplaySequence(HotkeyCategory::Window, "popup", getIApp()->getHotkeys()->getDisplaySequence(HotkeyCategory::Window,
{{"window"}})); "popup", {{"window"}}));
highlightNewMessagesAction_ = highlightNewMessagesAction_ =
new QAction("Mark Tab as Unread on New Messages", &this->menu_); new QAction("Mark Tab as Unread on New Messages", &this->menu_);
@@ -196,7 +196,7 @@ int NotebookTab::normalTabWidth()
float scale = this->scale(); float scale = this->scale();
int width; int width;
QFontMetrics metrics = getApp()->fonts->getFontMetrics( auto metrics = getIApp()->getFonts()->getFontMetrics(
FontStyle::UiTabs, float(qreal(this->scale()) * deviceDpi(this))); FontStyle::UiTabs, float(qreal(this->scale()) * deviceDpi(this)));
if (this->hasXButton()) if (this->hasXButton())
@@ -359,6 +359,11 @@ void NotebookTab::setHighlightState(HighlightState newHighlightStyle)
} }
} }
HighlightState NotebookTab::highlightState() const
{
return this->highlightState_;
}
void NotebookTab::setHighlightsEnabled(const bool &newVal) void NotebookTab::setHighlightsEnabled(const bool &newVal)
{ {
this->highlightNewMessagesAction_->setChecked(newVal); this->highlightNewMessagesAction_->setChecked(newVal);
@@ -783,6 +788,11 @@ void NotebookTab::wheelEvent(QWheelEvent *event)
} }
} }
void NotebookTab::update()
{
Button::update();
}
QRect NotebookTab::getXRect() QRect NotebookTab::getXRect()
{ {
QRect rect = this->rect(); QRect rect = this->rect();
+6
View File
@@ -53,6 +53,8 @@ public:
bool isLive() const; bool isLive() const;
void setHighlightState(HighlightState style); void setHighlightState(HighlightState style);
HighlightState highlightState() const;
void setHighlightsEnabled(const bool &newVal); void setHighlightsEnabled(const bool &newVal);
bool hasHighlightsEnabled() const; bool hasHighlightsEnabled() const;
@@ -84,6 +86,10 @@ protected:
void mouseMoveEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override;
void wheelEvent(QWheelEvent *event) override; void wheelEvent(QWheelEvent *event) override;
/// This exists as an alias to its base classes update, and is virtual
/// to allow for mocking
virtual void update();
private: private:
void showRenameDialog(); void showRenameDialog();
+1
View File
@@ -36,6 +36,7 @@ set(test_SOURCES
${CMAKE_CURRENT_LIST_DIR}/src/XDGDesktopFile.cpp ${CMAKE_CURRENT_LIST_DIR}/src/XDGDesktopFile.cpp
${CMAKE_CURRENT_LIST_DIR}/src/XDGHelper.cpp ${CMAKE_CURRENT_LIST_DIR}/src/XDGHelper.cpp
${CMAKE_CURRENT_LIST_DIR}/src/Selection.cpp ${CMAKE_CURRENT_LIST_DIR}/src/Selection.cpp
${CMAKE_CURRENT_LIST_DIR}/src/NotebookTab.cpp
# Add your new file above this line! # Add your new file above this line!
) )
+123
View File
@@ -0,0 +1,123 @@
#include "widgets/helper/NotebookTab.hpp"
#include "common/Literals.hpp"
#include "controllers/hotkeys/HotkeyController.hpp"
#include "gmock/gmock.h"
#include "mocks/EmptyApplication.hpp"
#include "singletons/Fonts.hpp"
#include "singletons/Theme.hpp"
#include "widgets/Notebook.hpp"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <QDebug>
#include <QString>
using namespace chatterino;
using ::testing::Exactly;
namespace {
class MockApplication : mock::EmptyApplication
{
public:
Theme *getThemes() override
{
return &this->theme;
}
HotkeyController *getHotkeys() override
{
return &this->hotkeys;
}
Fonts *getFonts() override
{
return &this->fonts;
}
Theme theme;
HotkeyController hotkeys;
Fonts fonts;
};
class MockNotebookTab : public NotebookTab
{
public:
explicit MockNotebookTab(Notebook *notebook)
: NotebookTab(notebook)
{
}
MOCK_METHOD(void, update, (), (override));
};
class NotebookTabFixture : public ::testing::Test
{
protected:
NotebookTabFixture()
: notebook(nullptr)
, tab(&this->notebook)
{
}
MockApplication mockApplication;
Notebook notebook;
MockNotebookTab tab;
};
} // namespace
/// The highlight state must settable
TEST_F(NotebookTabFixture, SetHighlightState)
{
EXPECT_CALL(this->tab, update).Times(Exactly(1));
EXPECT_EQ(this->tab.highlightState(), HighlightState::None);
this->tab.setHighlightState(HighlightState::NewMessage);
EXPECT_EQ(this->tab.highlightState(), HighlightState::NewMessage);
}
/// The highlight state must be able to "upgrade" from NewMessage to Highlighted
TEST_F(NotebookTabFixture, UpgradeHighlightState)
{
EXPECT_CALL(this->tab, update).Times(Exactly(2));
EXPECT_EQ(this->tab.highlightState(), HighlightState::None);
this->tab.setHighlightState(HighlightState::NewMessage);
EXPECT_EQ(this->tab.highlightState(), HighlightState::NewMessage);
this->tab.setHighlightState(HighlightState::Highlighted);
EXPECT_EQ(this->tab.highlightState(), HighlightState::Highlighted);
}
/// The highlight state must stay as NewMessage when called twice
TEST_F(NotebookTabFixture, SameHighlightStateNewMessage)
{
// XXX: This only updates the state once, so it should only update once
EXPECT_CALL(this->tab, update).Times(Exactly(2));
EXPECT_EQ(this->tab.highlightState(), HighlightState::None);
this->tab.setHighlightState(HighlightState::NewMessage);
EXPECT_EQ(this->tab.highlightState(), HighlightState::NewMessage);
this->tab.setHighlightState(HighlightState::NewMessage);
EXPECT_EQ(this->tab.highlightState(), HighlightState::NewMessage);
}
/// The highlight state must stay as Highlighted when called twice, and must not call update more than once
TEST_F(NotebookTabFixture, SameHighlightStateHighlighted)
{
EXPECT_CALL(this->tab, update).Times(Exactly(1));
EXPECT_EQ(this->tab.highlightState(), HighlightState::None);
this->tab.setHighlightState(HighlightState::Highlighted);
EXPECT_EQ(this->tab.highlightState(), HighlightState::Highlighted);
this->tab.setHighlightState(HighlightState::Highlighted);
EXPECT_EQ(this->tab.highlightState(), HighlightState::Highlighted);
}
/// The highlight state must not downgrade from Highlighted to NewMessage
TEST_F(NotebookTabFixture, DontDowngradeHighlightState)
{
EXPECT_CALL(this->tab, update).Times(Exactly(1));
EXPECT_EQ(this->tab.highlightState(), HighlightState::None);
this->tab.setHighlightState(HighlightState::Highlighted);
EXPECT_EQ(this->tab.highlightState(), HighlightState::Highlighted);
this->tab.setHighlightState(HighlightState::NewMessage);
EXPECT_EQ(this->tab.highlightState(), HighlightState::Highlighted);
}