Up unit test coverage of printer and label builder module
All checks were successful
Build ptprnt / build (push) Successful in 2m28s

This commit is contained in:
2025-10-19 14:57:26 +02:00
parent b24793bce6
commit 6009f0421d
4 changed files with 485 additions and 0 deletions

View File

@@ -113,6 +113,11 @@ bool FakePrinter::printMonochromeData(const graphics::MonochromeData& data) {
} }
bool FakePrinter::printLabel(const std::unique_ptr<graphics::ILabel> label) { bool FakePrinter::printLabel(const std::unique_ptr<graphics::ILabel> label) {
if (!label) {
spdlog::error("FakePrinter: Cannot print null label");
return false;
}
// Convert label directly to MonochromeData // Convert label directly to MonochromeData
// getRaw() returns data in Cairo surface coordinates matching getWidth() × getHeight() // getRaw() returns data in Cairo surface coordinates matching getWidth() × getHeight()
auto pixels = label->getRaw(); auto pixels = label->getRaw();

View File

@@ -0,0 +1,247 @@
/*
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 <gtest/gtest.h>
#include "graphics/Bitmap.hpp"
#include "graphics/Label.hpp"
#include "graphics/Monochrome.hpp"
#include "printers/FakePrinter.hpp"
namespace ptprnt::printer {
class FakePrinterTest : public ::testing::Test {
protected:
void SetUp() override {
printer = std::make_unique<FakePrinter>();
}
void TearDown() override { printer.reset(); }
std::unique_ptr<FakePrinter> printer;
};
// Test: Get driver name
TEST_F(FakePrinterTest, GetDriverName) {
auto name = printer->getDriverName();
EXPECT_FALSE(name.empty());
EXPECT_EQ(name, "FakePrinter");
}
// Test: Get printer name
TEST_F(FakePrinterTest, GetName) {
auto name = printer->getName();
EXPECT_FALSE(name.empty());
}
// Test: Get USB ID
TEST_F(FakePrinterTest, GetUsbId) {
auto usbId = printer->getUsbId();
EXPECT_EQ(usbId.first, 0x0000); // Virtual printer - no USB ID
EXPECT_EQ(usbId.second, 0x0000); // Virtual printer - no USB ID
}
// Test: Get printer version
TEST_F(FakePrinterTest, GetVersion) {
auto version = printer->getVersion();
EXPECT_FALSE(version.empty());
}
// Test: Get printer info
TEST_F(FakePrinterTest, GetPrinterInfo) {
auto info = printer->getPrinterInfo();
EXPECT_FALSE(info.driverName.empty());
EXPECT_FALSE(info.name.empty());
EXPECT_GT(info.pixelLines, 0);
}
// Test: Get printer status without device
TEST_F(FakePrinterTest, GetPrinterStatusWithoutDevice) {
auto status = printer->getPrinterStatus();
// FakePrinter should return empty status when no device attached
EXPECT_EQ(status.tapeWidthMm, 0);
}
// Test: Get printer status with device
TEST_F(FakePrinterTest, GetPrinterStatusWithDevice) {
printer->attachUsbDevice(nullptr);
auto status = printer->getPrinterStatus();
// FakePrinter should return default status when device attached
EXPECT_EQ(status.tapeWidthMm, 12); // Default tape width
}
// Test: Attach USB device (should always succeed for fake printer)
TEST_F(FakePrinterTest, AttachUsbDevice) {
bool result = printer->attachUsbDevice(nullptr);
// FakePrinter doesn't need a real device
EXPECT_TRUE(result);
}
// Test: Detach USB device
TEST_F(FakePrinterTest, DetachUsbDevice) {
printer->attachUsbDevice(nullptr);
bool result = printer->detachUsbDevice();
EXPECT_TRUE(result);
}
// Test: Print without attaching device first
TEST_F(FakePrinterTest, PrintWithoutDevice) {
bool result = printer->print();
// FakePrinter should fail if no device attached
EXPECT_FALSE(result);
}
// Test: Print after attaching device
TEST_F(FakePrinterTest, PrintWithDevice) {
printer->attachUsbDevice(nullptr);
bool result = printer->print();
EXPECT_TRUE(result);
}
// Test: Print bitmap
TEST_F(FakePrinterTest, PrintBitmap) {
graphics::Bitmap<graphics::ALPHA8> bitmap(100, 128);
// Fill with some pattern
std::vector<graphics::ALPHA8> pixels(bitmap.getWidth() * bitmap.getHeight());
for (size_t i = 0; i < pixels.size(); ++i) {
pixels[i] = (i % 2) ? 0xFF : 0x00;
}
bitmap.setPixels(pixels);
printer->attachUsbDevice(nullptr);
bool result = printer->printBitmap(bitmap);
EXPECT_TRUE(result);
// Check that last print was saved
const auto& lastPrint = printer->getLastPrint();
EXPECT_GT(lastPrint.getWidth(), 0);
EXPECT_GT(lastPrint.getHeight(), 0);
}
// Test: Print monochrome data
TEST_F(FakePrinterTest, PrintMonochromeData) {
graphics::Bitmap<graphics::ALPHA8> bitmap(50, 128);
auto pixels = bitmap.getPixelsCpy();
auto mono = graphics::Monochrome(pixels, bitmap.getWidth(), bitmap.getHeight());
auto data = mono.get();
printer->attachUsbDevice(nullptr);
bool result = printer->printMonochromeData(data);
EXPECT_TRUE(result);
// Verify last print
const auto& lastPrint = printer->getLastPrint();
EXPECT_GT(lastPrint.getWidth(), 0);
}
// Test: Print label
TEST_F(FakePrinterTest, PrintLabel) {
auto label = std::make_unique<graphics::Label>(128);
label->create("Test Label");
printer->attachUsbDevice(nullptr);
bool result = printer->printLabel(std::move(label));
EXPECT_TRUE(result);
}
// Test: Print null label
TEST_F(FakePrinterTest, PrintNullLabel) {
printer->attachUsbDevice(nullptr);
bool result = printer->printLabel(nullptr);
EXPECT_FALSE(result);
}
// Test: Print empty bitmap
TEST_F(FakePrinterTest, PrintEmptyBitmap) {
graphics::Bitmap<graphics::ALPHA8> bitmap(0, 0);
printer->attachUsbDevice(nullptr);
bool result = printer->printBitmap(bitmap);
// Should handle empty bitmap gracefully
EXPECT_TRUE(result);
}
// Test: Get last print before printing
TEST_F(FakePrinterTest, GetLastPrintBeforePrinting) {
// Should throw when getting last print before any print operation
EXPECT_THROW({
const auto& lastPrint = printer->getLastPrint();
(void)lastPrint; // Suppress unused variable warning
}, std::runtime_error);
}
// Test: Save last print to PNG (may fail without valid data)
TEST_F(FakePrinterTest, SaveLastPrintToPng) {
graphics::Bitmap<graphics::ALPHA8> bitmap(100, 128);
printer->attachUsbDevice(nullptr);
printer->printBitmap(bitmap);
// Try to save to /tmp
bool result = printer->saveLastPrintToPng("/tmp/test_fake_printer_output.png");
// Should succeed if we have valid print data
EXPECT_TRUE(result);
}
// Test: Multiple prints
TEST_F(FakePrinterTest, MultiplePrints) {
graphics::Bitmap<graphics::ALPHA8> bitmap1(50, 128);
graphics::Bitmap<graphics::ALPHA8> bitmap2(100, 128);
printer->attachUsbDevice(nullptr);
bool result1 = printer->printBitmap(bitmap1);
EXPECT_TRUE(result1);
bool result2 = printer->printBitmap(bitmap2);
EXPECT_TRUE(result2);
// Last print should be from second bitmap
const auto& lastPrint = printer->getLastPrint();
EXPECT_GT(lastPrint.getWidth(), 0);
}
// Test: Detach and reattach
TEST_F(FakePrinterTest, DetachAndReattach) {
printer->attachUsbDevice(nullptr);
EXPECT_TRUE(printer->detachUsbDevice());
// Should be able to reattach
EXPECT_TRUE(printer->attachUsbDevice(nullptr));
// Should be able to print after reattach
graphics::Bitmap<graphics::ALPHA8> bitmap(50, 128);
EXPECT_TRUE(printer->printBitmap(bitmap));
}
} // namespace ptprnt::printer

View File

@@ -0,0 +1,230 @@
/*
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 <gtest/gtest.h>
#include "graphics/LabelBuilder.hpp"
#include "graphics/interface/ILabel.hpp"
namespace ptprnt::graphics {
class LabelBuilderTest : public ::testing::Test {
protected:
void SetUp() override {
builder = std::make_unique<LabelBuilder>(128); // P700 printer height
}
void TearDown() override { builder.reset(); }
std::unique_ptr<LabelBuilder> builder;
};
// Test: Constructor
TEST_F(LabelBuilderTest, Constructor) {
EXPECT_NO_THROW(LabelBuilder(128));
EXPECT_NO_THROW(LabelBuilder(64));
}
// Test: Add single text
TEST_F(LabelBuilderTest, AddSingleText) {
auto& result = builder->addText("Hello");
// Should return reference to builder for chaining
EXPECT_EQ(&result, builder.get());
}
// Test: Add multiple texts
TEST_F(LabelBuilderTest, AddMultipleTexts) {
builder->addText("Line 1")
.addText("Line 2")
.addText("Line 3");
// Build should succeed
auto label = builder->build();
EXPECT_NE(label, nullptr);
}
// Test: Add empty text (should be ignored)
TEST_F(LabelBuilderTest, AddEmptyText) {
builder->addText("");
auto label = builder->build();
EXPECT_NE(label, nullptr);
}
// Test: Set font family
TEST_F(LabelBuilderTest, SetFontFamily) {
auto& result = builder->setFontFamily("monospace");
// Should return reference to builder for chaining
EXPECT_EQ(&result, builder.get());
}
// Test: Set font size
TEST_F(LabelBuilderTest, SetFontSize) {
auto& result = builder->setFontSize(24.0);
// Should return reference to builder for chaining
EXPECT_EQ(&result, builder.get());
}
// Test: Set horizontal alignment
TEST_F(LabelBuilderTest, SetHAlign) {
auto& result = builder->setHAlign(HAlignPosition::CENTER);
// Should return reference to builder for chaining
EXPECT_EQ(&result, builder.get());
}
// Test: Set vertical alignment
TEST_F(LabelBuilderTest, SetVAlign) {
auto& result = builder->setVAlign(VAlignPosition::TOP);
// Should return reference to builder for chaining
EXPECT_EQ(&result, builder.get());
}
// Test: Build with default settings
TEST_F(LabelBuilderTest, BuildWithDefaults) {
builder->addText("Test");
auto label = builder->build();
EXPECT_NE(label, nullptr);
EXPECT_GT(label->getWidth(), 0);
EXPECT_GT(label->getHeight(), 0);
}
// Test: Build with custom settings
TEST_F(LabelBuilderTest, BuildWithCustomSettings) {
builder->setFontFamily("serif")
.setFontSize(48.0)
.setHAlign(HAlignPosition::CENTER)
.setVAlign(VAlignPosition::MIDDLE)
.addText("Custom Text");
auto label = builder->build();
EXPECT_NE(label, nullptr);
}
// Test: Method chaining
TEST_F(LabelBuilderTest, MethodChaining) {
auto label = builder->setFontFamily("monospace")
.setFontSize(20.0)
.setHAlign(HAlignPosition::RIGHT)
.setVAlign(VAlignPosition::BOTTOM)
.addText("Chained")
.addText("Methods")
.build();
EXPECT_NE(label, nullptr);
}
// Test: Reset builder
TEST_F(LabelBuilderTest, Reset) {
builder->setFontFamily("monospace")
.setFontSize(48.0)
.setHAlign(HAlignPosition::RIGHT)
.setVAlign(VAlignPosition::BOTTOM)
.addText("Test");
auto& result = builder->reset();
// Should return reference to builder for chaining
EXPECT_EQ(&result, builder.get());
// After reset, should be able to build with defaults
builder->addText("After Reset");
auto label = builder->build();
EXPECT_NE(label, nullptr);
}
// Test: Build empty label
TEST_F(LabelBuilderTest, BuildEmptyLabel) {
// Build without adding any text
auto label = builder->build();
EXPECT_NE(label, nullptr);
}
// Test: Multiple builds from same builder
TEST_F(LabelBuilderTest, MultipleBuilds) {
builder->addText("First Build");
auto label1 = builder->build();
EXPECT_NE(label1, nullptr);
// Build again with same content
auto label2 = builder->build();
EXPECT_NE(label2, nullptr);
// Both labels should be valid
EXPECT_GT(label1->getWidth(), 0);
EXPECT_GT(label2->getWidth(), 0);
}
// Test: All horizontal alignments
TEST_F(LabelBuilderTest, AllHorizontalAlignments) {
builder->addText("Left").setHAlign(HAlignPosition::LEFT);
auto label1 = builder->build();
EXPECT_NE(label1, nullptr);
builder->reset().addText("Center").setHAlign(HAlignPosition::CENTER);
auto label2 = builder->build();
EXPECT_NE(label2, nullptr);
builder->reset().addText("Right").setHAlign(HAlignPosition::RIGHT);
auto label3 = builder->build();
EXPECT_NE(label3, nullptr);
builder->reset().addText("Justify").setHAlign(HAlignPosition::JUSTIFY);
auto label4 = builder->build();
EXPECT_NE(label4, nullptr);
}
// Test: All vertical alignments
TEST_F(LabelBuilderTest, AllVerticalAlignments) {
builder->addText("Top").setVAlign(VAlignPosition::TOP);
auto label1 = builder->build();
EXPECT_NE(label1, nullptr);
builder->reset().addText("Middle").setVAlign(VAlignPosition::MIDDLE);
auto label2 = builder->build();
EXPECT_NE(label2, nullptr);
builder->reset().addText("Bottom").setVAlign(VAlignPosition::BOTTOM);
auto label3 = builder->build();
EXPECT_NE(label3, nullptr);
}
// Test: Different font sizes
TEST_F(LabelBuilderTest, DifferentFontSizes) {
builder->setFontSize(12.0).addText("Small");
auto label1 = builder->build();
EXPECT_NE(label1, nullptr);
builder->reset().setFontSize(64.0).addText("Large");
auto label2 = builder->build();
EXPECT_NE(label2, nullptr);
// Larger font should produce wider label (assuming same text length)
// Note: This is a heuristic test and may not always be true depending on font rendering
}
} // namespace ptprnt::graphics

View File

@@ -5,13 +5,16 @@ test_sources = [
'bitmap_test/bitmap_test.cpp', 'bitmap_test/bitmap_test.cpp',
'monochrome_test/monochrome_test.cpp', 'monochrome_test/monochrome_test.cpp',
'label_test/label_test.cpp', 'label_test/label_test.cpp',
'label_builder_test/label_builder_test.cpp',
'printer_service_test/printer_service_test.cpp', 'printer_service_test/printer_service_test.cpp',
'p700_printer_test/p700_printer_test.cpp', 'p700_printer_test/p700_printer_test.cpp',
'fake_printer_test/fake_printer_test.cpp',
# Source files under test - graphics # Source files under test - graphics
'../src/graphics/Bitmap.cpp', '../src/graphics/Bitmap.cpp',
'../src/graphics/Monochrome.cpp', '../src/graphics/Monochrome.cpp',
'../src/graphics/Label.cpp', '../src/graphics/Label.cpp',
'../src/graphics/LabelBuilder.cpp',
# Source files under test - core # Source files under test - core
'../src/core/PrinterService.cpp', '../src/core/PrinterService.cpp',