All checks were successful
Build ptprnt / build (push) Successful in 3m52s
263 lines
9.6 KiB
C++
263 lines
9.6 KiB
C++
/*
|
|
ptrnt - print labels on linux
|
|
Copyright (C) 2025 Moritz Martinius
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#include "graphics/Label.hpp"
|
|
|
|
#include <gmock/gmock.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "../../tests/mocks/MockCairoWrapper.hpp"
|
|
#include "graphics/interface/ILabel.hpp"
|
|
|
|
using ::testing::_;
|
|
using ::testing::DoAll;
|
|
using ::testing::NiceMock;
|
|
using ::testing::Return;
|
|
using ::testing::SetArgPointee;
|
|
|
|
namespace ptprnt::graphics {
|
|
|
|
// Test fixture for Label tests with comprehensive mock setup
|
|
class LabelTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
mockWrapper = std::make_shared<NiceMock<MockCairoWrapper>>();
|
|
|
|
// Mock pointers for temporary surface (used in size calculation)
|
|
mockTempSurface = reinterpret_cast<cairo_surface_t*>(0x2000);
|
|
mockTempCr = reinterpret_cast<cairo_t*>(0x2001);
|
|
mockTempCtx = reinterpret_cast<PangoContext*>(0x2002);
|
|
mockTempLayout = reinterpret_cast<PangoLayout*>(0x2003);
|
|
|
|
// Mock pointers for final surface (used in rendering)
|
|
mockFinalSurface = reinterpret_cast<cairo_surface_t*>(0x3000);
|
|
mockFinalCr = reinterpret_cast<cairo_t*>(0x3001);
|
|
mockFinalCtx = reinterpret_cast<PangoContext*>(0x3002);
|
|
mockFinalLayout = reinterpret_cast<PangoLayout*>(0x3003);
|
|
|
|
// Mock font description
|
|
mockFontDesc = reinterpret_cast<PangoFontDescription*>(0x2004);
|
|
|
|
// Default layout size: 100x30 pixels (in PANGO_SCALE units)
|
|
defaultLayoutWidth = 100;
|
|
defaultLayoutHeight = 30;
|
|
|
|
SetupDefaultBehaviors();
|
|
}
|
|
|
|
void SetupDefaultBehaviors() {
|
|
// Font map
|
|
ON_CALL(*mockWrapper, pango_cairo_font_map_new())
|
|
.WillByDefault(Return(reinterpret_cast<PangoFontMap*>(0x1000)));
|
|
|
|
// Temporary surface creation (for size calculation)
|
|
ON_CALL(*mockWrapper, cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1)).WillByDefault(Return(mockTempSurface));
|
|
ON_CALL(*mockWrapper, cairo_create(mockTempSurface)).WillByDefault(Return(mockTempCr));
|
|
ON_CALL(*mockWrapper, pango_cairo_create_context(mockTempCr)).WillByDefault(Return(mockTempCtx));
|
|
ON_CALL(*mockWrapper, pango_layout_new(mockTempCtx)).WillByDefault(Return(mockTempLayout));
|
|
|
|
// Final surface creation (for rendering) - use _ for width since it varies
|
|
ON_CALL(*mockWrapper, cairo_image_surface_create(CAIRO_FORMAT_A8, _, _))
|
|
.WillByDefault(Return(mockFinalSurface));
|
|
ON_CALL(*mockWrapper, cairo_create(mockFinalSurface)).WillByDefault(Return(mockFinalCr));
|
|
ON_CALL(*mockWrapper, pango_cairo_create_context(mockFinalCr)).WillByDefault(Return(mockFinalCtx));
|
|
ON_CALL(*mockWrapper, pango_layout_new(mockFinalCtx)).WillByDefault(Return(mockFinalLayout));
|
|
|
|
// Font description
|
|
ON_CALL(*mockWrapper, pango_font_description_new()).WillByDefault(Return(mockFontDesc));
|
|
|
|
// Layout size - return default dimensions
|
|
ON_CALL(*mockWrapper, pango_layout_get_size(_, _, _))
|
|
.WillByDefault(DoAll(SetArgPointee<1>(defaultLayoutWidth * PANGO_SCALE),
|
|
SetArgPointee<2>(defaultLayoutHeight * PANGO_SCALE)));
|
|
|
|
// Surface status - always success
|
|
ON_CALL(*mockWrapper, cairo_surface_status(_)).WillByDefault(Return(CAIRO_STATUS_SUCCESS));
|
|
|
|
// Surface properties for getRaw()
|
|
ON_CALL(*mockWrapper, cairo_image_surface_get_format(_)).WillByDefault(Return(CAIRO_FORMAT_A8));
|
|
ON_CALL(*mockWrapper, cairo_image_surface_get_width(_)).WillByDefault(Return(defaultLayoutWidth));
|
|
ON_CALL(*mockWrapper, cairo_image_surface_get_height(_)).WillByDefault(Return(128));
|
|
ON_CALL(*mockWrapper, cairo_image_surface_get_stride(_)).WillByDefault(Return(defaultLayoutWidth));
|
|
|
|
// Mock data pointer
|
|
mockSurfaceData.resize(defaultLayoutWidth * 128, 0xFF);
|
|
ON_CALL(*mockWrapper, cairo_image_surface_get_data(_)).WillByDefault(Return(mockSurfaceData.data()));
|
|
}
|
|
|
|
// Helper method to set custom layout dimensions
|
|
void SetLayoutSize(int width, int height) {
|
|
defaultLayoutWidth = width;
|
|
defaultLayoutHeight = height;
|
|
|
|
// Update the mock to return new dimensions
|
|
ON_CALL(*mockWrapper, pango_layout_get_size(_, _, _))
|
|
.WillByDefault(DoAll(SetArgPointee<1>(width * PANGO_SCALE), SetArgPointee<2>(height * PANGO_SCALE)));
|
|
|
|
ON_CALL(*mockWrapper, cairo_image_surface_get_width(_)).WillByDefault(Return(width));
|
|
ON_CALL(*mockWrapper, cairo_image_surface_get_stride(_)).WillByDefault(Return(width));
|
|
|
|
// Resize mock data
|
|
mockSurfaceData.resize(width * 128, 0xFF);
|
|
ON_CALL(*mockWrapper, cairo_image_surface_get_data(_)).WillByDefault(Return(mockSurfaceData.data()));
|
|
}
|
|
|
|
std::shared_ptr<NiceMock<MockCairoWrapper>> mockWrapper;
|
|
|
|
// Mock pointers
|
|
cairo_surface_t* mockTempSurface;
|
|
cairo_t* mockTempCr;
|
|
PangoContext* mockTempCtx;
|
|
PangoLayout* mockTempLayout;
|
|
|
|
cairo_surface_t* mockFinalSurface;
|
|
cairo_t* mockFinalCr;
|
|
PangoContext* mockFinalCtx;
|
|
PangoLayout* mockFinalLayout;
|
|
|
|
PangoFontDescription* mockFontDesc;
|
|
|
|
// Default layout dimensions
|
|
int defaultLayoutWidth;
|
|
int defaultLayoutHeight;
|
|
|
|
// Mock surface data
|
|
std::vector<unsigned char> mockSurfaceData;
|
|
};
|
|
|
|
// Smoke test with real Cairo/Pango
|
|
TEST(basic_test, Label_smokeTest_succeeds) {
|
|
auto label = Label(128);
|
|
EXPECT_EQ(label.getHeight(), 128);
|
|
EXPECT_EQ(label.getWidth(), 0); // No label created yet
|
|
}
|
|
|
|
// Constructor test with mock
|
|
TEST_F(LabelTest, Constructor_InitializesFontMap) {
|
|
EXPECT_CALL(*mockWrapper, pango_cairo_font_map_new()).Times(1);
|
|
|
|
auto label = Label(128, mockWrapper);
|
|
|
|
EXPECT_EQ(label.getHeight(), 128);
|
|
EXPECT_EQ(label.getWidth(), 0);
|
|
}
|
|
|
|
// Test getters before label creation
|
|
TEST_F(LabelTest, Getters_BeforeCreate_ReturnDefaults) {
|
|
auto label = Label(256, mockWrapper);
|
|
|
|
EXPECT_EQ(label.getHeight(), 256);
|
|
EXPECT_EQ(label.getWidth(), 0);
|
|
}
|
|
|
|
// Test setters
|
|
TEST_F(LabelTest, Setters_ModifyProperties) {
|
|
auto label = Label(128, mockWrapper);
|
|
|
|
label.setFontSize(24.0);
|
|
label.setFontFamily("Arial");
|
|
label.setText("Test");
|
|
label.setHAlign(HAlignPosition::CENTER);
|
|
label.setVAlign(VAlignPosition::BOTTOM);
|
|
|
|
// Properties are set (no way to verify without create, but no crash is good)
|
|
SUCCEED();
|
|
}
|
|
|
|
// Test create() - basic functionality with simplified setup
|
|
TEST_F(LabelTest, Create_WithText_Succeeds) {
|
|
auto label = Label(128, mockWrapper);
|
|
label.setFontSize(12.0);
|
|
label.setFontFamily("Sans");
|
|
|
|
bool result = label.create("Hello");
|
|
|
|
EXPECT_TRUE(result);
|
|
EXPECT_EQ(label.getWidth(), defaultLayoutWidth);
|
|
EXPECT_EQ(label.getHeight(), 128);
|
|
}
|
|
|
|
// Test horizontal alignment - RIGHT
|
|
TEST_F(LabelTest, Create_WithRightAlignment_SetsCorrectPangoAlignment) {
|
|
auto label = Label(128, mockWrapper);
|
|
label.setHAlign(HAlignPosition::RIGHT);
|
|
|
|
// Verify RIGHT alignment is set (temp + final layout)
|
|
EXPECT_CALL(*mockWrapper, pango_layout_set_alignment(_, PANGO_ALIGN_RIGHT)).Times(2);
|
|
|
|
label.create("Right");
|
|
}
|
|
|
|
// Test horizontal alignment - JUSTIFY
|
|
TEST_F(LabelTest, Create_WithJustifyAlignment_SetsJustifyAndAlignment) {
|
|
auto label = Label(128, mockWrapper);
|
|
label.setHAlign(HAlignPosition::JUSTIFY);
|
|
|
|
// Verify JUSTIFY requires LEFT alignment + justify flag
|
|
EXPECT_CALL(*mockWrapper, pango_layout_set_alignment(_, PANGO_ALIGN_LEFT)).Times(2);
|
|
EXPECT_CALL(*mockWrapper, pango_layout_set_justify(_, true)).Times(2);
|
|
#if PANGO_VERSION_MAJOR >= 1 && PANGO_VERSION_MINOR >= 50
|
|
EXPECT_CALL(*mockWrapper, pango_layout_set_justify_last_line(_, true)).Times(2);
|
|
#endif
|
|
|
|
label.create("Justify");
|
|
}
|
|
|
|
// Test vertical alignment - TOP (no cairo_move_to)
|
|
TEST_F(LabelTest, Create_WithTopAlignment_NoMoveToCall) {
|
|
auto label = Label(128, mockWrapper);
|
|
label.setVAlign(VAlignPosition::TOP);
|
|
|
|
// TOP alignment should NOT call cairo_move_to
|
|
EXPECT_CALL(*mockWrapper, cairo_move_to(_, _, _)).Times(0);
|
|
|
|
label.create("Top");
|
|
}
|
|
|
|
// Test vertical alignment - BOTTOM
|
|
TEST_F(LabelTest, Create_WithBottomAlignment_CallsMoveToWithCorrectOffset) {
|
|
auto label = Label(128, mockWrapper);
|
|
label.setVAlign(VAlignPosition::BOTTOM);
|
|
|
|
SetLayoutSize(50, 20); // Use helper to set custom size
|
|
|
|
// BOTTOM alignment: offset = printerHeight - layoutHeight = 128 - 20 = 108
|
|
EXPECT_CALL(*mockWrapper, cairo_move_to(mockFinalCr, 0.0, 108.0)).Times(1);
|
|
|
|
label.create("Bottom");
|
|
}
|
|
|
|
// Test vertical alignment - MIDDLE
|
|
TEST_F(LabelTest, Create_WithMiddleAlignment_CallsMoveToWithCenteredOffset) {
|
|
auto label = Label(128, mockWrapper);
|
|
label.setVAlign(VAlignPosition::MIDDLE);
|
|
|
|
SetLayoutSize(50, 20); // Use helper to set custom size
|
|
|
|
// MIDDLE alignment: offset = (printerHeight - layoutHeight) / 2 = (128 - 20) / 2 = 54
|
|
EXPECT_CALL(*mockWrapper, cairo_move_to(mockFinalCr, 0.0, 54.0)).Times(1);
|
|
|
|
label.create("Middle");
|
|
}
|
|
|
|
} // namespace ptprnt::graphics
|