This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
package wpdf
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHexToColor(t *testing.T) {
|
||||
cases := []struct {
|
||||
in uint32
|
||||
want PDFColor
|
||||
}{
|
||||
{0x000000, PDFColor{R: 0, G: 0, B: 0}},
|
||||
{0xFFFFFF, PDFColor{R: 255, G: 255, B: 255}},
|
||||
{0xFF0000, PDFColor{R: 255, G: 0, B: 0}},
|
||||
{0x00FF00, PDFColor{R: 0, G: 255, B: 0}},
|
||||
{0x0000FF, PDFColor{R: 0, G: 0, B: 255}},
|
||||
{0x123456, PDFColor{R: 0x12, G: 0x34, B: 0x56}},
|
||||
{0xC0C0C0, PDFColor{R: 192, G: 192, B: 192}},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got := hexToColor(c.in)
|
||||
if got != c.want {
|
||||
t.Errorf("hexToColor(%#x) = %+v, want %+v", c.in, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHexToColorIgnoresHigherBits(t *testing.T) {
|
||||
got := hexToColor(0xFF123456)
|
||||
want := PDFColor{R: 0x12, G: 0x34, B: 0x56}
|
||||
if got != want {
|
||||
t.Errorf("hexToColor(0xFF123456) = %+v, want %+v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRgbToColor(t *testing.T) {
|
||||
got := rgbToColor(10, 20, 30)
|
||||
want := PDFColor{R: 10, G: 20, B: 30}
|
||||
if got != want {
|
||||
t.Errorf("rgbToColor(10,20,30) = %+v, want %+v", got, want)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
package wpdf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func newBuilderWithPage(t *testing.T) *WPDFBuilder {
|
||||
t.Helper()
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
b.AddPage()
|
||||
return b
|
||||
}
|
||||
|
||||
func TestNewPDFBuilderDefaults(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
|
||||
if b == nil {
|
||||
t.Fatal("expected non-nil builder")
|
||||
}
|
||||
if b.FPDF() == nil {
|
||||
t.Fatal("expected non-nil underlying gofpdf builder")
|
||||
}
|
||||
|
||||
if b.fontName != FontHelvetica {
|
||||
t.Errorf("default fontName = %v, want %v", b.fontName, FontHelvetica)
|
||||
}
|
||||
if b.fontStyle != Normal {
|
||||
t.Errorf("default fontStyle = %v, want %v", b.fontStyle, Normal)
|
||||
}
|
||||
if b.fontSize != 12 {
|
||||
t.Errorf("default fontSize = %v, want 12", b.fontSize)
|
||||
}
|
||||
|
||||
left, top, right, _ := b.GetMargins()
|
||||
if left != 15 || top != 25 || right != 15 {
|
||||
t.Errorf("default margins = (%v, %v, %v), want (15, 25, 15)", left, top, right)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPDFBuilderUnicode(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, true)
|
||||
if b.tr == nil {
|
||||
t.Fatal("expected unicode translator to be set")
|
||||
}
|
||||
// Translator should not panic on simple ASCII input
|
||||
out := b.tr("hello")
|
||||
if out == "" {
|
||||
t.Errorf("translator returned empty string for non-empty input")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPDFBuilderNonUnicode(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
if got := b.tr("hello"); got != "hello" {
|
||||
t.Errorf("non-unicode translator = %q, want %q", got, "hello")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPDFBuilderLandscape(t *testing.T) {
|
||||
b := NewPDFBuilder(Landscape, SizeA4, false)
|
||||
w, h := b.GetPageSize()
|
||||
if w <= h {
|
||||
t.Errorf("landscape: expected width>height, got w=%v h=%v", w, h)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewPDFBuilderPortrait(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
w, h := b.GetPageSize()
|
||||
if h <= w {
|
||||
t.Errorf("portrait: expected height>width, got w=%v h=%v", w, h)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetMargins(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
b.SetMargins(PDFMargins{Left: 5, Top: 10, Right: 7})
|
||||
|
||||
if got := b.GetMarginLeft(); got != 5 {
|
||||
t.Errorf("MarginLeft = %v, want 5", got)
|
||||
}
|
||||
if got := b.GetMarginTop(); got != 10 {
|
||||
t.Errorf("MarginTop = %v, want 10", got)
|
||||
}
|
||||
if got := b.GetMarginRight(); got != 7 {
|
||||
t.Errorf("MarginRight = %v, want 7", got)
|
||||
}
|
||||
// MarginBottom is not set explicitly via SetMargins, just verify accessor doesn't panic.
|
||||
_ = b.GetMarginBottom()
|
||||
}
|
||||
|
||||
func TestGetWorkAreaWidth(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
b.SetMargins(PDFMargins{Left: 10, Top: 20, Right: 5})
|
||||
pw := b.GetPageWidth()
|
||||
want := pw - 10 - 5
|
||||
if got := b.GetWorkAreaWidth(); got != want {
|
||||
t.Errorf("GetWorkAreaWidth = %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPageWidthHeight(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
w, h := b.GetPageSize()
|
||||
if got := b.GetPageWidth(); got != w {
|
||||
t.Errorf("PageWidth = %v, want %v", got, w)
|
||||
}
|
||||
if got := b.GetPageHeight(); got != h {
|
||||
t.Errorf("PageHeight = %v, want %v", got, h)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetGetTextColor(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.SetTextColor(10, 20, 30)
|
||||
r, g, bl := b.GetTextColor()
|
||||
if r != 10 || g != 20 || bl != 30 {
|
||||
t.Errorf("GetTextColor = (%d,%d,%d), want (10,20,30)", r, g, bl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetGetDrawColor(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.SetDrawColor(40, 50, 60)
|
||||
r, g, bl := b.GetDrawColor()
|
||||
if r != 40 || g != 50 || bl != 60 {
|
||||
t.Errorf("GetDrawColor = (%d,%d,%d), want (40,50,60)", r, g, bl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetGetFillColor(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.SetFillColor(70, 80, 90)
|
||||
r, g, bl := b.GetFillColor()
|
||||
if r != 70 || g != 80 || bl != 90 {
|
||||
t.Errorf("GetFillColor = (%d,%d,%d), want (70,80,90)", r, g, bl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetGetLineWidth(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.SetLineWidth(2.5)
|
||||
if got := b.GetLineWidth(); got != 2.5 {
|
||||
t.Errorf("LineWidth = %v, want 2.5", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetFont(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.SetFont(FontTimes, Bold, 16)
|
||||
if b.fontName != FontTimes {
|
||||
t.Errorf("fontName = %v, want %v", b.fontName, FontTimes)
|
||||
}
|
||||
if b.fontStyle != Bold {
|
||||
t.Errorf("fontStyle = %v, want %v", b.fontStyle, Bold)
|
||||
}
|
||||
if got := b.GetFontSize(); got != 16 {
|
||||
t.Errorf("FontSize = %v, want 16", got)
|
||||
}
|
||||
if b.cellHeight <= 0 {
|
||||
t.Errorf("cellHeight must be >0 after SetFont, got %v", b.cellHeight)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetCellSpacing(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.SetCellSpacing(3.5)
|
||||
if b.cellSpacing != 3.5 {
|
||||
t.Errorf("cellSpacing = %v, want 3.5", b.cellSpacing)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetGetXY(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
|
||||
b.SetX(50)
|
||||
if got := b.GetX(); got != 50 {
|
||||
t.Errorf("X = %v, want 50", got)
|
||||
}
|
||||
|
||||
b.SetY(60)
|
||||
if got := b.GetY(); got != 60 {
|
||||
t.Errorf("Y = %v, want 60", got)
|
||||
}
|
||||
|
||||
b.SetXY(70, 80)
|
||||
x, y := b.GetXY()
|
||||
if x != 70 || y != 80 {
|
||||
t.Errorf("GetXY = (%v,%v), want (70,80)", x, y)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIncX(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.SetX(10)
|
||||
b.IncX(5)
|
||||
if got := b.GetX(); got != 15 {
|
||||
t.Errorf("after IncX: X = %v, want 15", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebug(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
if b.debug != false {
|
||||
t.Errorf("default debug = %v, want false", b.debug)
|
||||
}
|
||||
b.Debug(true)
|
||||
if !b.debug {
|
||||
t.Errorf("Debug(true) did not enable debug")
|
||||
}
|
||||
b.Debug(false)
|
||||
if b.debug {
|
||||
t.Errorf("Debug(false) did not disable debug")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPageNo(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
if got := b.PageNo(); got != 0 {
|
||||
t.Errorf("PageNo before AddPage = %v, want 0", got)
|
||||
}
|
||||
b.AddPage()
|
||||
if got := b.PageNo(); got != 1 {
|
||||
t.Errorf("PageNo after first AddPage = %v, want 1", got)
|
||||
}
|
||||
b.AddPage()
|
||||
if got := b.PageNo(); got != 2 {
|
||||
t.Errorf("PageNo after second AddPage = %v, want 2", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildEmpty(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
b.AddPage()
|
||||
bin, err := b.Build()
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error: %v", err)
|
||||
}
|
||||
if len(bin) == 0 {
|
||||
t.Fatal("Build() returned empty bytes")
|
||||
}
|
||||
// PDFs start with "%PDF-"
|
||||
if !bytes.HasPrefix(bin, []byte("%PDF-")) {
|
||||
t.Errorf("Build() output does not start with %%PDF- header: %q", bin[:min(10, len(bin))])
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildWithContent(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
b.AddPage()
|
||||
b.Cell("Hello", NewPDFCellOpt().Width(50))
|
||||
b.Ln(5)
|
||||
b.MultiCell("multiline content")
|
||||
b.Rect(10, 10, RectFill, NewPDFRectOpt().X(20).Y(20).FillColor(255, 0, 0))
|
||||
b.Line(0, 0, 100, 100, NewPDFLineOpt().LineWidth(0.5))
|
||||
|
||||
bin, err := b.Build()
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error: %v", err)
|
||||
}
|
||||
if !bytes.HasPrefix(bin, []byte("%PDF-")) {
|
||||
t.Errorf("Build() output does not start with %%PDF- header")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetStringWidth(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
w := b.GetStringWidth("Hello")
|
||||
if w <= 0 {
|
||||
t.Errorf("GetStringWidth = %v, want >0", w)
|
||||
}
|
||||
|
||||
wLong := b.GetStringWidth("Hello, this is a longer string")
|
||||
if wLong <= w {
|
||||
t.Errorf("longer string should have wider width: short=%v long=%v", w, wLong)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetStringWidthWithFontOverride(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.SetFont(FontHelvetica, Normal, 10)
|
||||
|
||||
wSmall := b.GetStringWidth("Hello", *NewPDFCellOpt().FontSize(10))
|
||||
wLarge := b.GetStringWidth("Hello", *NewPDFCellOpt().FontSize(40))
|
||||
|
||||
if wLarge <= wSmall {
|
||||
t.Errorf("larger font should yield wider string: small=%v large=%v", wSmall, wLarge)
|
||||
}
|
||||
|
||||
// Original font must be restored.
|
||||
if b.fontSize != 10 {
|
||||
t.Errorf("font size not restored: %v, want 10", b.fontSize)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetAutoPageBreak(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.SetAutoPageBreak(true, 10)
|
||||
enabled, margin := b.FPDF().GetAutoPageBreak()
|
||||
if !enabled || margin != 10 {
|
||||
t.Errorf("AutoPageBreak = (%v, %v), want (true, 10)", enabled, margin)
|
||||
}
|
||||
|
||||
b.SetAutoPageBreak(false, 0)
|
||||
enabled, _ = b.FPDF().GetAutoPageBreak()
|
||||
if enabled {
|
||||
t.Errorf("AutoPageBreak should be disabled")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetFooterFunc(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
called := false
|
||||
b.SetFooterFunc(func() { called = true })
|
||||
b.AddPage()
|
||||
_, err := b.Build()
|
||||
if err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
if !called {
|
||||
t.Errorf("footer func was not called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBookmark(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
// Should not panic
|
||||
b.Bookmark("section 1", 0, b.GetY())
|
||||
|
||||
_, err := b.Build()
|
||||
if err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLnAdvancesY(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.SetXY(20, 50)
|
||||
b.Ln(10)
|
||||
if y := b.GetY(); y <= 50 {
|
||||
t.Errorf("Ln did not advance Y: before=50, after=%v", y)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebugAddPage(t *testing.T) {
|
||||
// Test with debug = true to cover that branch
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
b.Debug(true)
|
||||
b.AddPage()
|
||||
// Just verify Build still works
|
||||
_, err := b.Build()
|
||||
if err != nil {
|
||||
t.Fatalf("Build with debug page error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebugLn(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
b.AddPage()
|
||||
b.Debug(true)
|
||||
b.SetXY(20, 50)
|
||||
b.Ln(10)
|
||||
_, err := b.Build()
|
||||
if err != nil {
|
||||
t.Fatalf("Build with debug Ln error: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
package wpdf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCellWithAllOptions(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
|
||||
b.Cell("test",
|
||||
NewPDFCellOpt().
|
||||
Width(40).
|
||||
Height(8).
|
||||
Border(BorderFull).
|
||||
LnPos(BreakToNextLine).
|
||||
Align(AlignHorzCenter).
|
||||
FillBackground(true).
|
||||
Font(FontTimes, Bold, 10).
|
||||
LnAfter(2).
|
||||
TextColor(255, 0, 0).
|
||||
BorderColor(0, 255, 0).
|
||||
FillColor(0, 0, 255).
|
||||
Alpha(0.5, BlendMultiply))
|
||||
|
||||
out, err := b.Build()
|
||||
if err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
if !bytes.HasPrefix(out, []byte("%PDF-")) {
|
||||
t.Error("output not a PDF")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCellRestoresFont(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.SetFont(FontHelvetica, Normal, 12)
|
||||
|
||||
b.Cell("text", NewPDFCellOpt().Width(50).Font(FontTimes, Bold, 20))
|
||||
|
||||
if b.fontName != FontHelvetica {
|
||||
t.Errorf("fontName not restored: %v", b.fontName)
|
||||
}
|
||||
if b.fontStyle != Normal {
|
||||
t.Errorf("fontStyle not restored: %v", b.fontStyle)
|
||||
}
|
||||
if b.fontSize != 12 {
|
||||
t.Errorf("fontSize not restored: %v", b.fontSize)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCellRestoresColors(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.SetTextColor(10, 20, 30)
|
||||
b.SetDrawColor(40, 50, 60)
|
||||
b.SetFillColor(70, 80, 90)
|
||||
|
||||
b.Cell("text",
|
||||
NewPDFCellOpt().Width(50).
|
||||
TextColor(1, 2, 3).
|
||||
BorderColor(4, 5, 6).
|
||||
FillColor(7, 8, 9))
|
||||
|
||||
r, g, bl := b.GetTextColor()
|
||||
if r != 10 || g != 20 || bl != 30 {
|
||||
t.Errorf("TextColor not restored: (%d,%d,%d)", r, g, bl)
|
||||
}
|
||||
|
||||
r, g, bl = b.GetDrawColor()
|
||||
if r != 40 || g != 50 || bl != 60 {
|
||||
t.Errorf("DrawColor not restored: (%d,%d,%d)", r, g, bl)
|
||||
}
|
||||
|
||||
r, g, bl = b.GetFillColor()
|
||||
if r != 70 || g != 80 || bl != 90 {
|
||||
t.Errorf("FillColor not restored: (%d,%d,%d)", r, g, bl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCellAutoWidth(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
|
||||
startX := b.GetX()
|
||||
b.Cell("Hello", NewPDFCellOpt().AutoWidth().AutoWidthPaddingX(2).LnPos(BreakToRight))
|
||||
|
||||
endX := b.GetX()
|
||||
if endX <= startX {
|
||||
t.Errorf("AutoWidth: X did not advance (start=%v end=%v)", startX, endX)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCellWithExplicitX(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
|
||||
b.Cell("text", NewPDFCellOpt().Width(50).X(70).LnPos(BreakToRight))
|
||||
// X should be 70 + 50 = 120 after cell with BreakToRight
|
||||
if got := b.GetX(); got < 120-0.01 || got > 120+0.01 {
|
||||
t.Errorf("X after cell at X=70 with width=50 = %v, want ~120", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCellWithDebugTrueBreakToRight(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.Debug(true)
|
||||
b.Cell("text", NewPDFCellOpt().Width(20).LnPos(BreakToRight))
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCellWithDebugTrueBreakToBelow(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.Debug(true)
|
||||
b.Cell("text", NewPDFCellOpt().Width(20).LnPos(BreakToBelow))
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiCellAllOptions(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.MultiCell("hello\nworld",
|
||||
NewPDFMultiCellOpt().
|
||||
Width(50).
|
||||
Height(6).
|
||||
Border(BorderFull).
|
||||
Align(AlignLeft).
|
||||
FillBackground(true).
|
||||
Font(FontTimes, Italic, 10).
|
||||
LnAfter(1).
|
||||
X(20).
|
||||
TextColor(1, 2, 3).
|
||||
BorderColor(4, 5, 6).
|
||||
FillColor(7, 8, 9).
|
||||
Alpha(0.5, BlendNormal))
|
||||
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiCellRestoresFont(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.SetFont(FontHelvetica, Normal, 12)
|
||||
|
||||
b.MultiCell("text", NewPDFMultiCellOpt().Width(50).Font(FontTimes, Bold, 20))
|
||||
|
||||
if b.fontName != FontHelvetica {
|
||||
t.Errorf("fontName not restored: %v", b.fontName)
|
||||
}
|
||||
if b.fontStyle != Normal {
|
||||
t.Errorf("fontStyle not restored: %v", b.fontStyle)
|
||||
}
|
||||
if b.fontSize != 12 {
|
||||
t.Errorf("fontSize not restored: %v", b.fontSize)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiCellWithDebug(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.Debug(true)
|
||||
b.MultiCell("hello world", NewPDFMultiCellOpt().Width(50))
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRectAllOptions(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.Rect(20, 10, RectFillOutline,
|
||||
NewPDFRectOpt().
|
||||
X(15).Y(20).
|
||||
LineWidth(0.5).
|
||||
DrawColor(10, 20, 30).
|
||||
FillColor(100, 110, 120).
|
||||
Alpha(0.5, BlendNormal).
|
||||
Rounded(2))
|
||||
|
||||
// Drawing color and line width should be restored after Rect.
|
||||
r, g, bl := b.GetDrawColor()
|
||||
if r != 0 || g != 0 || bl != 0 {
|
||||
t.Errorf("draw color not restored: (%d,%d,%d)", r, g, bl)
|
||||
}
|
||||
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRectStyles(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.Rect(10, 10, RectFill, NewPDFRectOpt().X(10).Y(10).FillColor(255, 0, 0))
|
||||
b.Rect(10, 10, RectOutline, NewPDFRectOpt().X(30).Y(10).DrawColor(0, 255, 0))
|
||||
b.Rect(10, 10, RectFillOutline, NewPDFRectOpt().X(50).Y(10).FillColor(0, 0, 255).DrawColor(255, 255, 0))
|
||||
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRectIndividualRadii(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.Rect(20, 20, RectOutline,
|
||||
NewPDFRectOpt().
|
||||
X(10).Y(10).
|
||||
RadiusTL(2).RadiusTR(3).RadiusBR(4).RadiusBL(5))
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLineAllOptions(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.Line(10, 10, 100, 100,
|
||||
NewPDFLineOpt().
|
||||
LineWidth(0.5).
|
||||
DrawColor(255, 0, 0).
|
||||
Alpha(0.7, BlendDarken).
|
||||
CapRound())
|
||||
|
||||
// Line width should be restored after Line.
|
||||
if got := b.GetLineWidth(); got == 0.5 {
|
||||
t.Errorf("LineWidth was not restored: %v", got)
|
||||
}
|
||||
|
||||
r, g, bl := b.GetDrawColor()
|
||||
if r == 255 && g == 0 && bl == 0 {
|
||||
t.Error("DrawColor not restored")
|
||||
}
|
||||
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLineCapStyles(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.Line(10, 10, 100, 10, NewPDFLineOpt().LineWidth(2).CapButt())
|
||||
b.Line(10, 20, 100, 20, NewPDFLineOpt().LineWidth(2).CapRound())
|
||||
b.Line(10, 30, 100, 30, NewPDFLineOpt().LineWidth(2).CapSquare())
|
||||
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCellWithExtraLn(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
yBefore := b.GetY()
|
||||
b.Cell("text", NewPDFCellOpt().Width(50).LnAfter(5))
|
||||
yAfter := b.GetY()
|
||||
if yAfter <= yBefore {
|
||||
t.Errorf("Y did not advance after Cell with LnAfter")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiCellWithExtraLn(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
yBefore := b.GetY()
|
||||
b.MultiCell("multiline\ntext", NewPDFMultiCellOpt().Width(50).LnAfter(5))
|
||||
yAfter := b.GetY()
|
||||
if yAfter <= yBefore {
|
||||
t.Errorf("Y did not advance after MultiCell with LnAfter")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package wpdf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func makeTestPNG(t *testing.T, w, h int) []byte {
|
||||
t.Helper()
|
||||
img := image.NewRGBA(image.Rect(0, 0, w, h))
|
||||
for y := range h {
|
||||
for x := range w {
|
||||
img.Set(x, y, color.RGBA{R: uint8(x), G: uint8(y), B: 128, A: 255})
|
||||
}
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := png.Encode(&buf, img); err != nil {
|
||||
t.Fatalf("png encode: %v", err)
|
||||
}
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func TestRegisterImageDetectsPNG(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
b.AddPage()
|
||||
|
||||
bin := makeTestPNG(t, 16, 16)
|
||||
ref := b.RegisterImage(bin)
|
||||
|
||||
if ref == nil {
|
||||
t.Fatal("RegisterImage returned nil")
|
||||
}
|
||||
if !strings.HasPrefix(ref.Name, "fpdf_img_") {
|
||||
t.Errorf("default name not prefixed: %q", ref.Name)
|
||||
}
|
||||
if ref.Mime != "image/png" {
|
||||
t.Errorf("mime = %q, want image/png", ref.Mime)
|
||||
}
|
||||
if ref.Info == nil {
|
||||
t.Error("info is nil")
|
||||
}
|
||||
if !bytes.Equal(ref.Bin, bin) {
|
||||
t.Error("Bin not stored correctly")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterImageWithCustomName(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
b.AddPage()
|
||||
|
||||
bin := makeTestPNG(t, 8, 8)
|
||||
ref := b.RegisterImage(bin, NewPDFImageRegisterOpt().Name("custom_image"))
|
||||
|
||||
if ref.Name != "custom_image" {
|
||||
t.Errorf("custom name not used: %q", ref.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterImageWithExplicitType(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
b.AddPage()
|
||||
|
||||
bin := makeTestPNG(t, 8, 8)
|
||||
ref := b.RegisterImage(bin, NewPDFImageRegisterOpt().ImageType("PNG"))
|
||||
|
||||
if ref.Info == nil {
|
||||
t.Error("info is nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterImageLargeBuffer(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
b.AddPage()
|
||||
|
||||
// Larger than 512 bytes to exercise that branch in detection.
|
||||
bin := makeTestPNG(t, 256, 256)
|
||||
if len(bin) <= 512 {
|
||||
t.Fatalf("test png unexpectedly small: %d bytes", len(bin))
|
||||
}
|
||||
ref := b.RegisterImage(bin)
|
||||
|
||||
if ref.Mime != "image/png" {
|
||||
t.Errorf("mime = %q, want image/png", ref.Mime)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageDrawing(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
b.AddPage()
|
||||
|
||||
bin := makeTestPNG(t, 16, 16)
|
||||
ref := b.RegisterImage(bin)
|
||||
|
||||
b.Image(ref, NewPDFImageOpt().X(10).Y(10).Width(20).Height(20))
|
||||
|
||||
out, err := b.Build()
|
||||
if err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
if !bytes.HasPrefix(out, []byte("%PDF-")) {
|
||||
t.Error("output not a PDF")
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageDrawingDefaults(t *testing.T) {
|
||||
b := NewPDFBuilder(Portrait, SizeA4, false)
|
||||
b.AddPage()
|
||||
|
||||
bin := makeTestPNG(t, 16, 16)
|
||||
ref := b.RegisterImage(bin)
|
||||
|
||||
b.Image(ref) // no opts: use info defaults
|
||||
|
||||
out, err := b.Build()
|
||||
if err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
if !bytes.HasPrefix(out, []byte("%PDF-")) {
|
||||
t.Error("output not a PDF")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,455 @@
|
||||
package wpdf
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPDFCellOptBuilders(t *testing.T) {
|
||||
opt := NewPDFCellOpt().
|
||||
Width(100).
|
||||
Height(20).
|
||||
Border(BorderFull).
|
||||
LnPos(BreakToRight).
|
||||
Align(AlignHorzCenter).
|
||||
FillBackground(true).
|
||||
Link(5).
|
||||
LinkStr("https://example.com").
|
||||
Font(FontTimes, Bold, 14).
|
||||
LnAfter(2).
|
||||
X(15).
|
||||
AutoWidth().
|
||||
AutoWidthPaddingX(3).
|
||||
TextColor(1, 2, 3).
|
||||
BorderColor(4, 5, 6).
|
||||
FillColor(7, 8, 9).
|
||||
Alpha(0.5, BlendMultiply).
|
||||
Debug(true)
|
||||
|
||||
if opt.width == nil || *opt.width != 100 {
|
||||
t.Error("width not set")
|
||||
}
|
||||
if opt.height == nil || *opt.height != 20 {
|
||||
t.Error("height not set")
|
||||
}
|
||||
if opt.border == nil || *opt.border != BorderFull {
|
||||
t.Error("border not set")
|
||||
}
|
||||
if opt.ln == nil || *opt.ln != BreakToRight {
|
||||
t.Error("ln not set")
|
||||
}
|
||||
if opt.align == nil || *opt.align != AlignHorzCenter {
|
||||
t.Error("align not set")
|
||||
}
|
||||
if opt.fill == nil || *opt.fill != true {
|
||||
t.Error("fill not set")
|
||||
}
|
||||
if opt.link == nil || *opt.link != 5 {
|
||||
t.Error("link not set")
|
||||
}
|
||||
if opt.linkStr == nil || *opt.linkStr != "https://example.com" {
|
||||
t.Error("linkStr not set")
|
||||
}
|
||||
if opt.fontNameOverride == nil || *opt.fontNameOverride != FontTimes {
|
||||
t.Error("fontNameOverride not set")
|
||||
}
|
||||
if opt.fontStyleOverride == nil || *opt.fontStyleOverride != Bold {
|
||||
t.Error("fontStyleOverride not set")
|
||||
}
|
||||
if opt.fontSizeOverride == nil || *opt.fontSizeOverride != 14 {
|
||||
t.Error("fontSizeOverride not set")
|
||||
}
|
||||
if opt.extraLn == nil || *opt.extraLn != 2 {
|
||||
t.Error("extraLn not set")
|
||||
}
|
||||
if opt.x == nil || *opt.x != 15 {
|
||||
t.Error("x not set")
|
||||
}
|
||||
if opt.autoWidth == nil || *opt.autoWidth != true {
|
||||
t.Error("autoWidth not set")
|
||||
}
|
||||
if opt.autoWidthPaddingX == nil || *opt.autoWidthPaddingX != 3 {
|
||||
t.Error("autoWidthPaddingX not set")
|
||||
}
|
||||
if opt.textColor == nil || *opt.textColor != (PDFColor{R: 1, G: 2, B: 3}) {
|
||||
t.Error("textColor not set")
|
||||
}
|
||||
if opt.borderColor == nil || *opt.borderColor != (PDFColor{R: 4, G: 5, B: 6}) {
|
||||
t.Error("borderColor not set")
|
||||
}
|
||||
if opt.fillColor == nil || *opt.fillColor != (PDFColor{R: 7, G: 8, B: 9}) {
|
||||
t.Error("fillColor not set")
|
||||
}
|
||||
if opt.alphaOverride == nil || opt.alphaOverride.V1 != 0.5 || opt.alphaOverride.V2 != BlendMultiply {
|
||||
t.Error("alphaOverride not set")
|
||||
}
|
||||
if opt.debug == nil || *opt.debug != true {
|
||||
t.Error("debug not set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFCellOptHexColors(t *testing.T) {
|
||||
opt := NewPDFCellOpt().
|
||||
TextColorHex(0xFF0000).
|
||||
BorderColorHex(0x00FF00).
|
||||
FillColorHex(0x0000FF)
|
||||
|
||||
if *opt.textColor != (PDFColor{R: 0xFF, G: 0, B: 0}) {
|
||||
t.Errorf("textColorHex got %+v", opt.textColor)
|
||||
}
|
||||
if *opt.borderColor != (PDFColor{R: 0, G: 0xFF, B: 0}) {
|
||||
t.Errorf("borderColorHex got %+v", opt.borderColor)
|
||||
}
|
||||
if *opt.fillColor != (PDFColor{R: 0, G: 0, B: 0xFF}) {
|
||||
t.Errorf("fillColorHex got %+v", opt.fillColor)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFCellOptBoldItalic(t *testing.T) {
|
||||
opt := NewPDFCellOpt().Bold()
|
||||
if opt.fontStyleOverride == nil || *opt.fontStyleOverride != Bold {
|
||||
t.Error("Bold() should set fontStyleOverride to Bold")
|
||||
}
|
||||
|
||||
opt2 := NewPDFCellOpt().Italic()
|
||||
if opt2.fontStyleOverride == nil || *opt2.fontStyleOverride != Italic {
|
||||
t.Error("Italic() should set fontStyleOverride to Italic")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFCellOptIndividualFontSetters(t *testing.T) {
|
||||
opt := NewPDFCellOpt().FontName(FontCourier).FontStyle(Italic).FontSize(11)
|
||||
if *opt.fontNameOverride != FontCourier {
|
||||
t.Error("FontName")
|
||||
}
|
||||
if *opt.fontStyleOverride != Italic {
|
||||
t.Error("FontStyle")
|
||||
}
|
||||
if *opt.fontSizeOverride != 11 {
|
||||
t.Error("FontSize")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFCellOptCopy(t *testing.T) {
|
||||
orig := NewPDFCellOpt().Width(50).Height(10)
|
||||
cp := orig.Copy()
|
||||
|
||||
if cp == orig {
|
||||
t.Error("Copy() returned same pointer")
|
||||
}
|
||||
if *cp.width != 50 || *cp.height != 10 {
|
||||
t.Error("copied opt does not match original")
|
||||
}
|
||||
|
||||
cp.Width(99)
|
||||
if *orig.width != 50 {
|
||||
t.Errorf("modifying copy affected original: orig.width=%v", *orig.width)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFCellOptToMulti(t *testing.T) {
|
||||
cell := NewPDFCellOpt().
|
||||
Width(100).
|
||||
Height(20).
|
||||
Border(BorderTop).
|
||||
Align(AlignRight).
|
||||
FillBackground(true).
|
||||
Font(FontTimes, Bold, 14).
|
||||
LnAfter(3).
|
||||
X(5).
|
||||
TextColor(1, 2, 3).
|
||||
BorderColor(4, 5, 6).
|
||||
FillColor(7, 8, 9)
|
||||
|
||||
multi := cell.ToMulti()
|
||||
|
||||
if multi == nil {
|
||||
t.Fatal("ToMulti returned nil")
|
||||
}
|
||||
if *multi.width != 100 {
|
||||
t.Error("width not transferred")
|
||||
}
|
||||
if *multi.height != 20 {
|
||||
t.Error("height not transferred")
|
||||
}
|
||||
if *multi.border != BorderTop {
|
||||
t.Error("border not transferred")
|
||||
}
|
||||
if *multi.align != AlignRight {
|
||||
t.Error("align not transferred")
|
||||
}
|
||||
if !*multi.fill {
|
||||
t.Error("fill not transferred")
|
||||
}
|
||||
if *multi.fontNameOverride != FontTimes {
|
||||
t.Error("fontName not transferred")
|
||||
}
|
||||
if *multi.fontStyleOverride != Bold {
|
||||
t.Error("fontStyle not transferred")
|
||||
}
|
||||
if *multi.fontSizeOverride != 14 {
|
||||
t.Error("fontSize not transferred")
|
||||
}
|
||||
if *multi.extraLn != 3 {
|
||||
t.Error("extraLn not transferred")
|
||||
}
|
||||
if *multi.x != 5 {
|
||||
t.Error("x not transferred")
|
||||
}
|
||||
if *multi.textColor != (PDFColor{R: 1, G: 2, B: 3}) {
|
||||
t.Error("textColor not transferred")
|
||||
}
|
||||
if *multi.borderColor != (PDFColor{R: 4, G: 5, B: 6}) {
|
||||
t.Error("borderColor not transferred")
|
||||
}
|
||||
if *multi.fillColor != (PDFColor{R: 7, G: 8, B: 9}) {
|
||||
t.Error("fillColor not transferred")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFMultiCellOptBuilders(t *testing.T) {
|
||||
opt := NewPDFMultiCellOpt().
|
||||
Width(80).
|
||||
Height(10).
|
||||
Border(BorderFull).
|
||||
Align(AlignLeft).
|
||||
FillBackground(true).
|
||||
Font(FontTimes, Italic, 11).
|
||||
LnAfter(1).
|
||||
X(5).
|
||||
TextColor(10, 20, 30).
|
||||
BorderColor(40, 50, 60).
|
||||
FillColor(70, 80, 90).
|
||||
Alpha(0.7, BlendScreen).
|
||||
Debug(true)
|
||||
|
||||
if *opt.width != 80 || *opt.height != 10 || *opt.border != BorderFull {
|
||||
t.Error("base opts not set")
|
||||
}
|
||||
if *opt.align != AlignLeft || !*opt.fill {
|
||||
t.Error("align/fill not set")
|
||||
}
|
||||
if *opt.fontNameOverride != FontTimes || *opt.fontStyleOverride != Italic || *opt.fontSizeOverride != 11 {
|
||||
t.Error("font not set")
|
||||
}
|
||||
if *opt.extraLn != 1 || *opt.x != 5 {
|
||||
t.Error("layout opts not set")
|
||||
}
|
||||
if *opt.textColor != (PDFColor{R: 10, G: 20, B: 30}) {
|
||||
t.Error("textColor not set")
|
||||
}
|
||||
if *opt.borderColor != (PDFColor{R: 40, G: 50, B: 60}) {
|
||||
t.Error("borderColor not set")
|
||||
}
|
||||
if *opt.fillColor != (PDFColor{R: 70, G: 80, B: 90}) {
|
||||
t.Error("fillColor not set")
|
||||
}
|
||||
if opt.alphaOverride.V1 != 0.7 || opt.alphaOverride.V2 != BlendScreen {
|
||||
t.Error("alpha not set")
|
||||
}
|
||||
if !*opt.debug {
|
||||
t.Error("debug not set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFMultiCellOptHexColors(t *testing.T) {
|
||||
opt := NewPDFMultiCellOpt().
|
||||
TextColorHex(0xAABBCC).
|
||||
BorderColorHex(0x112233).
|
||||
FillColorHex(0x445566)
|
||||
|
||||
if *opt.textColor != (PDFColor{R: 0xAA, G: 0xBB, B: 0xCC}) {
|
||||
t.Error("textColorHex")
|
||||
}
|
||||
if *opt.borderColor != (PDFColor{R: 0x11, G: 0x22, B: 0x33}) {
|
||||
t.Error("borderColorHex")
|
||||
}
|
||||
if *opt.fillColor != (PDFColor{R: 0x44, G: 0x55, B: 0x66}) {
|
||||
t.Error("fillColorHex")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFMultiCellOptBoldItalic(t *testing.T) {
|
||||
if *NewPDFMultiCellOpt().Bold().fontStyleOverride != Bold {
|
||||
t.Error("MultiCell Bold")
|
||||
}
|
||||
if *NewPDFMultiCellOpt().Italic().fontStyleOverride != Italic {
|
||||
t.Error("MultiCell Italic")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFMultiCellOptIndividualFontSetters(t *testing.T) {
|
||||
opt := NewPDFMultiCellOpt().FontName(FontCourier).FontStyle(Bold).FontSize(11)
|
||||
if *opt.fontNameOverride != FontCourier {
|
||||
t.Error("FontName")
|
||||
}
|
||||
if *opt.fontStyleOverride != Bold {
|
||||
t.Error("FontStyle")
|
||||
}
|
||||
if *opt.fontSizeOverride != 11 {
|
||||
t.Error("FontSize")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFMultiCellOptCopy(t *testing.T) {
|
||||
orig := NewPDFMultiCellOpt().Width(50)
|
||||
cp := orig.Copy()
|
||||
if cp == orig {
|
||||
t.Error("Copy() returned same pointer")
|
||||
}
|
||||
cp.Width(99)
|
||||
if *orig.width != 50 {
|
||||
t.Error("modifying copy affected original")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFRectOptBuilders(t *testing.T) {
|
||||
opt := NewPDFRectOpt().
|
||||
X(5).Y(6).
|
||||
LineWidth(0.3).
|
||||
DrawColor(10, 20, 30).
|
||||
FillColor(40, 50, 60).
|
||||
Alpha(0.4, BlendOverlay).
|
||||
Rounded(2).
|
||||
Debug(true)
|
||||
|
||||
if *opt.x != 5 || *opt.y != 6 {
|
||||
t.Error("x/y not set")
|
||||
}
|
||||
if *opt.lineWidth != 0.3 {
|
||||
t.Error("lineWidth not set")
|
||||
}
|
||||
if *opt.drawColor != (PDFColor{R: 10, G: 20, B: 30}) {
|
||||
t.Error("drawColor not set")
|
||||
}
|
||||
if *opt.fillColor != (PDFColor{R: 40, G: 50, B: 60}) {
|
||||
t.Error("fillColor not set")
|
||||
}
|
||||
if opt.alpha.V1 != 0.4 || opt.alpha.V2 != BlendOverlay {
|
||||
t.Error("alpha not set")
|
||||
}
|
||||
if *opt.radiusTL != 2 || *opt.radiusTR != 2 || *opt.radiusBL != 2 || *opt.radiusBR != 2 {
|
||||
t.Error("Rounded did not set all four corners")
|
||||
}
|
||||
if !*opt.debug {
|
||||
t.Error("debug not set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFRectOptIndividualRadii(t *testing.T) {
|
||||
opt := NewPDFRectOpt().RadiusTL(1).RadiusTR(2).RadiusBR(3).RadiusBL(4)
|
||||
|
||||
if *opt.radiusTL != 1 || *opt.radiusTR != 2 || *opt.radiusBR != 3 || *opt.radiusBL != 4 {
|
||||
t.Errorf("individual radii not set: TL=%v TR=%v BR=%v BL=%v",
|
||||
*opt.radiusTL, *opt.radiusTR, *opt.radiusBR, *opt.radiusBL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFRectOptHexColors(t *testing.T) {
|
||||
opt := NewPDFRectOpt().DrawColorHex(0xABCDEF).FillColorHex(0x123456)
|
||||
if *opt.drawColor != (PDFColor{R: 0xAB, G: 0xCD, B: 0xEF}) {
|
||||
t.Error("drawColorHex")
|
||||
}
|
||||
if *opt.fillColor != (PDFColor{R: 0x12, G: 0x34, B: 0x56}) {
|
||||
t.Error("fillColorHex")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFLineOptBuilders(t *testing.T) {
|
||||
opt := NewPDFLineOpt().
|
||||
LineWidth(0.5).
|
||||
DrawColor(10, 20, 30).
|
||||
Alpha(0.3, BlendDarken).
|
||||
CapButt().
|
||||
Debug(true)
|
||||
|
||||
if *opt.lineWidth != 0.5 {
|
||||
t.Error("lineWidth not set")
|
||||
}
|
||||
if *opt.drawColor != (PDFColor{R: 10, G: 20, B: 30}) {
|
||||
t.Error("drawColor not set")
|
||||
}
|
||||
if opt.alpha.V1 != 0.3 || opt.alpha.V2 != BlendDarken {
|
||||
t.Error("alpha not set")
|
||||
}
|
||||
if *opt.capStyle != CapButt {
|
||||
t.Error("capStyle CapButt not set")
|
||||
}
|
||||
if !*opt.debug {
|
||||
t.Error("debug not set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFLineOptCapStyles(t *testing.T) {
|
||||
if *NewPDFLineOpt().CapButt().capStyle != CapButt {
|
||||
t.Error("CapButt")
|
||||
}
|
||||
if *NewPDFLineOpt().CapRound().capStyle != CapRound {
|
||||
t.Error("CapRound")
|
||||
}
|
||||
if *NewPDFLineOpt().CapSquare().capStyle != CapSquare {
|
||||
t.Error("CapSquare")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFLineOptHexColor(t *testing.T) {
|
||||
opt := NewPDFLineOpt().DrawColorHex(0xFEDCBA)
|
||||
if *opt.drawColor != (PDFColor{R: 0xFE, G: 0xDC, B: 0xBA}) {
|
||||
t.Error("drawColorHex")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFImageRegisterOptBuilders(t *testing.T) {
|
||||
opt := NewPDFImageRegisterOpt().
|
||||
ImageType("PNG").
|
||||
ReadDpi(true).
|
||||
AllowNegativePosition(true).
|
||||
Name("custom_name")
|
||||
|
||||
if *opt.imageType != "PNG" {
|
||||
t.Error("imageType not set")
|
||||
}
|
||||
if !*opt.readDpi {
|
||||
t.Error("readDpi not set")
|
||||
}
|
||||
if !*opt.allowNegativePosition {
|
||||
t.Error("allowNegativePosition not set")
|
||||
}
|
||||
if *opt.name != "custom_name" {
|
||||
t.Error("name not set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPDFImageOptBuilders(t *testing.T) {
|
||||
opt := NewPDFImageOpt().
|
||||
X(1).Y(2).Width(30).Height(40).
|
||||
Flow(false).
|
||||
Link(7).LinkStr("foo").
|
||||
ImageType("PNG").
|
||||
ReadDpi(true).
|
||||
AllowNegativePosition(true).
|
||||
Crop(0.1, 0.2, 0.3, 0.4).
|
||||
Alpha(0.6, BlendMultiply).
|
||||
Debug(true)
|
||||
|
||||
if *opt.x != 1 || *opt.y != 2 || *opt.width != 30 || *opt.height != 40 {
|
||||
t.Error("position/size not set")
|
||||
}
|
||||
if *opt.flow != false {
|
||||
t.Error("flow not set")
|
||||
}
|
||||
if *opt.link != 7 || *opt.linkStr != "foo" {
|
||||
t.Error("link not set")
|
||||
}
|
||||
if *opt.imageType != "PNG" || !*opt.readDpi || !*opt.allowNegativePosition {
|
||||
t.Error("image options not set")
|
||||
}
|
||||
if opt.crop == nil || opt.crop.CropX != 0.1 || opt.crop.CropY != 0.2 || opt.crop.CropWidth != 0.3 || opt.crop.CropHeight != 0.4 {
|
||||
t.Errorf("crop not set: %+v", opt.crop)
|
||||
}
|
||||
if opt.alphaOverride.V1 != 0.6 || opt.alphaOverride.V2 != BlendMultiply {
|
||||
t.Error("alpha not set")
|
||||
}
|
||||
if !*opt.debug {
|
||||
t.Error("debug not set")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,553 @@
|
||||
package wpdf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTableBuilderInitialState(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
tb := b.Table()
|
||||
|
||||
if tb == nil {
|
||||
t.Fatal("Table() returned nil")
|
||||
}
|
||||
if tb.builder != b {
|
||||
t.Error("builder back-reference not set")
|
||||
}
|
||||
if tb.padx != 2 {
|
||||
t.Errorf("default padx = %v, want 2", tb.padx)
|
||||
}
|
||||
if tb.pady != 2 {
|
||||
t.Errorf("default pady = %v, want 2", tb.pady)
|
||||
}
|
||||
if tb.defaultCellStyle == nil {
|
||||
t.Error("default cell style is nil")
|
||||
}
|
||||
if tb.RowCount() != 0 {
|
||||
t.Errorf("RowCount = %v, want 0", tb.RowCount())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderConfig(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
style := NewTableCellStyleOpt()
|
||||
tb := b.Table().
|
||||
PadX(5).
|
||||
PadY(7).
|
||||
Widths("10", "20", "auto").
|
||||
DefaultStyle(style).
|
||||
Debug(true)
|
||||
|
||||
if tb.padx != 5 {
|
||||
t.Errorf("padx = %v, want 5", tb.padx)
|
||||
}
|
||||
if tb.pady != 7 {
|
||||
t.Errorf("pady = %v, want 7", tb.pady)
|
||||
}
|
||||
if tb.columnWidths == nil || len(*tb.columnWidths) != 3 {
|
||||
t.Errorf("columnWidths not set correctly: %v", tb.columnWidths)
|
||||
}
|
||||
if tb.defaultCellStyle != style {
|
||||
t.Error("defaultCellStyle not set")
|
||||
}
|
||||
if tb.debug == nil || !*tb.debug {
|
||||
t.Error("debug not set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderAddRowDefault(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
tb := b.Table().AddRowDefaultStyle("a", "b", "c")
|
||||
if tb.RowCount() != 1 {
|
||||
t.Errorf("RowCount = %v, want 1", tb.RowCount())
|
||||
}
|
||||
if len(tb.rows[0].cells) != 3 {
|
||||
t.Errorf("cells = %v, want 3", len(tb.rows[0].cells))
|
||||
}
|
||||
if tb.rows[0].cells[0].Content != "a" {
|
||||
t.Errorf("cell[0].Content = %q, want %q", tb.rows[0].cells[0].Content, "a")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderAddRowWithStyle(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
style := NewTableCellStyleOpt().Bold().FontSize(10)
|
||||
|
||||
tb := b.Table().AddRowWithStyle(style, "x", "y")
|
||||
if tb.RowCount() != 1 {
|
||||
t.Fatalf("RowCount = %v, want 1", tb.RowCount())
|
||||
}
|
||||
if len(tb.rows[0].cells) != 2 {
|
||||
t.Fatalf("cells = %v, want 2", len(tb.rows[0].cells))
|
||||
}
|
||||
for i, c := range tb.rows[0].cells {
|
||||
if c.Style.fontStyleOverride == nil || *c.Style.fontStyleOverride != Bold {
|
||||
t.Errorf("cell[%d] style not Bold", i)
|
||||
}
|
||||
if c.Style.fontSizeOverride == nil || *c.Style.fontSizeOverride != 10 {
|
||||
t.Errorf("cell[%d] fontSize not 10", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderAddRow(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
tc := TableCell{Content: "hello", Style: TableCellStyleOpt{}}
|
||||
tb := b.Table().AddRow(tc, tc)
|
||||
if tb.RowCount() != 1 || len(tb.rows[0].cells) != 2 {
|
||||
t.Errorf("AddRow did not add expected cells")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderBuildRowFlow(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
|
||||
tb := b.Table().
|
||||
BuildRow().Cell("a").Cell("b").Cell("c").BuildRow().
|
||||
BuildRow().Cells("d", "e", "f").BuildRow()
|
||||
|
||||
if tb.RowCount() != 2 {
|
||||
t.Errorf("RowCount = %v, want 2", tb.RowCount())
|
||||
}
|
||||
if len(tb.rows[0].cells) != 3 || len(tb.rows[1].cells) != 3 {
|
||||
t.Errorf("each row should have 3 cells; got %d and %d",
|
||||
len(tb.rows[0].cells), len(tb.rows[1].cells))
|
||||
}
|
||||
if tb.rows[0].cells[0].Content != "a" || tb.rows[1].cells[2].Content != "f" {
|
||||
t.Error("cell content mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableRowBuilderCellWithStyle(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
style := NewTableCellStyleOpt().Bold()
|
||||
tb := b.Table().BuildRow().CellWithStyle("x", style).BuildRow()
|
||||
|
||||
if tb.rows[0].cells[0].Style.fontStyleOverride == nil ||
|
||||
*tb.rows[0].cells[0].Style.fontStyleOverride != Bold {
|
||||
t.Error("cell style not applied")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableRowBuilderCellObjects(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
c1 := TableCell{Content: "alpha"}
|
||||
c2 := TableCell{Content: "beta"}
|
||||
|
||||
tb := b.Table().BuildRow().CellObject(c1).CellObjects(c2).BuildRow()
|
||||
if len(tb.rows[0].cells) != 2 {
|
||||
t.Fatalf("cells = %v, want 2", len(tb.rows[0].cells))
|
||||
}
|
||||
if tb.rows[0].cells[0].Content != "alpha" || tb.rows[0].cells[1].Content != "beta" {
|
||||
t.Error("cell objects not added")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableRowBuilderRowStyle(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
rowStyle := NewTableCellStyleOpt().Italic()
|
||||
|
||||
tb := b.Table().BuildRow().RowStyle(rowStyle).Cell("x").Cell("y").BuildRow()
|
||||
|
||||
for i, c := range tb.rows[0].cells {
|
||||
if c.Style.fontStyleOverride == nil || *c.Style.fontStyleOverride != Italic {
|
||||
t.Errorf("cell[%d] should use row style (Italic)", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableMaxFontSize(t *testing.T) {
|
||||
row := tableRow{
|
||||
cells: []TableCell{
|
||||
{Style: *NewTableCellStyleOpt().FontSize(10)},
|
||||
{Style: *NewTableCellStyleOpt().FontSize(20)},
|
||||
{Style: *NewTableCellStyleOpt().FontSize(15)},
|
||||
},
|
||||
}
|
||||
got := row.maxFontSize(8)
|
||||
if got != 20 {
|
||||
t.Errorf("maxFontSize = %v, want 20", got)
|
||||
}
|
||||
|
||||
rowEmpty := tableRow{cells: []TableCell{{Style: TableCellStyleOpt{}}}}
|
||||
got = rowEmpty.maxFontSize(12)
|
||||
if got != 12 {
|
||||
t.Errorf("maxFontSize default = %v, want 12", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderBuildEmpty(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
// Should not panic when no rows
|
||||
b.Table().Build()
|
||||
}
|
||||
|
||||
func TestTableBuilderBuildNumeric(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.Table().
|
||||
Widths("30", "30", "30").
|
||||
AddRowDefaultStyle("a", "b", "c").
|
||||
AddRowDefaultStyle("d", "e", "f").
|
||||
Build()
|
||||
|
||||
bin, err := b.Build()
|
||||
if err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
if !bytes.HasPrefix(bin, []byte("%PDF-")) {
|
||||
t.Error("output not a PDF")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderBuildAuto(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.Table().
|
||||
Widths("auto", "auto", "auto").
|
||||
AddRowDefaultStyle("a", "b", "c").
|
||||
Build()
|
||||
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderBuildFr(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.Table().
|
||||
Widths("1fr", "2fr", "*").
|
||||
AddRowDefaultStyle("a", "b", "c").
|
||||
Build()
|
||||
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderMixedColumnSpecs(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.Table().
|
||||
Widths("auto", "30", "1fr", "*").
|
||||
AddRowDefaultStyle("a", "b", "c", "d").
|
||||
AddRowDefaultStyle("longer text here", "x", "y", "z").
|
||||
Build()
|
||||
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderNoColumnsDefined(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
// When Widths not specified, table uses "*" for each cell of first row
|
||||
b.Table().
|
||||
AddRowDefaultStyle("a", "b").
|
||||
AddRowDefaultStyle("c", "d").
|
||||
Build()
|
||||
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderMismatchedColumnCount(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.Table().
|
||||
Widths("10", "10").
|
||||
AddRowDefaultStyle("a", "b", "c"). // wrong column count
|
||||
Build()
|
||||
|
||||
// Should produce an error in the underlying gofpdf, surfaced by Build()
|
||||
_, err := b.Build()
|
||||
if err == nil {
|
||||
t.Error("expected error for mismatched column count, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderInvalidColumnWidth(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.Table().
|
||||
Widths("not-a-number").
|
||||
AddRowDefaultStyle("a").
|
||||
Build()
|
||||
|
||||
_, err := b.Build()
|
||||
if err == nil {
|
||||
t.Error("expected error for invalid column width, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderMultiCellRow(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
style := NewTableCellStyleOpt().MultiCell(true)
|
||||
b.Table().
|
||||
Widths("auto", "1fr").
|
||||
AddRowWithStyle(style, "a", "Multi line\ntext content").
|
||||
Build()
|
||||
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderEllipsizeRow(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
style := NewTableCellStyleOpt().MultiCell(false).Ellipsize(true)
|
||||
b.Table().
|
||||
Widths("20").
|
||||
AddRowWithStyle(style, "this is a very long text that should be ellipsized").
|
||||
Build()
|
||||
|
||||
if _, err := b.Build(); err != nil {
|
||||
t.Fatalf("Build error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableBuilderDefaultTableStyle(t *testing.T) {
|
||||
s := defaultTableStyle()
|
||||
if s == nil {
|
||||
t.Fatal("defaultTableStyle returned nil")
|
||||
}
|
||||
if s.minWidth == nil || *s.minWidth != 5 {
|
||||
t.Errorf("default minWidth = %v, want 5", s.minWidth)
|
||||
}
|
||||
if s.ellipsize == nil || !*s.ellipsize {
|
||||
t.Errorf("default ellipsize should be true")
|
||||
}
|
||||
if s.multiCell == nil || *s.multiCell {
|
||||
t.Errorf("default multiCell should be false")
|
||||
}
|
||||
if s.fontSizeOverride == nil || *s.fontSizeOverride != 8 {
|
||||
t.Errorf("default font size = %v, want 8", s.fontSizeOverride)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableCellStyleOptBuilders(t *testing.T) {
|
||||
o := NewTableCellStyleOpt().
|
||||
MultiCell(true).
|
||||
Ellipsize(false).
|
||||
PaddingHorz(3).
|
||||
MinWidth(7).
|
||||
FillHeight(true)
|
||||
|
||||
if !*o.multiCell {
|
||||
t.Error("multiCell")
|
||||
}
|
||||
if *o.ellipsize {
|
||||
t.Error("ellipsize")
|
||||
}
|
||||
if *o.paddingHorz != 3 {
|
||||
t.Error("paddingHorz")
|
||||
}
|
||||
if *o.minWidth != 7 {
|
||||
t.Error("minWidth")
|
||||
}
|
||||
if !*o.fillHeight {
|
||||
t.Error("fillHeight")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableCellStyleOptCellStyle(t *testing.T) {
|
||||
cell := *NewPDFCellOpt().Width(50).Bold()
|
||||
o := NewTableCellStyleOpt().CellStyle(cell)
|
||||
|
||||
if o.PDFCellOpt.width == nil || *o.PDFCellOpt.width != 50 {
|
||||
t.Error("CellStyle did not transfer width")
|
||||
}
|
||||
if o.PDFCellOpt.fontStyleOverride == nil || *o.PDFCellOpt.fontStyleOverride != Bold {
|
||||
t.Error("CellStyle did not transfer style")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableCellStyleOptDelegates(t *testing.T) {
|
||||
o := NewTableCellStyleOpt().
|
||||
Width(10).
|
||||
Height(20).
|
||||
Border(BorderFull).
|
||||
LnPos(BreakToBelow).
|
||||
Align(AlignRight).
|
||||
FillBackground(true).
|
||||
Link(5).
|
||||
LinkStr("link").
|
||||
Font(FontTimes, Bold, 11).
|
||||
LnAfter(2).
|
||||
X(3).
|
||||
AutoWidth().
|
||||
AutoWidthPaddingX(1).
|
||||
TextColor(1, 2, 3).
|
||||
BorderColor(4, 5, 6).
|
||||
FillColor(7, 8, 9).
|
||||
Alpha(0.5, BlendNormal).
|
||||
Debug(true)
|
||||
|
||||
if *o.PDFCellOpt.width != 10 {
|
||||
t.Error("width")
|
||||
}
|
||||
if *o.PDFCellOpt.height != 20 {
|
||||
t.Error("height")
|
||||
}
|
||||
if *o.PDFCellOpt.border != BorderFull {
|
||||
t.Error("border")
|
||||
}
|
||||
if *o.PDFCellOpt.ln != BreakToBelow {
|
||||
t.Error("ln")
|
||||
}
|
||||
if *o.PDFCellOpt.align != AlignRight {
|
||||
t.Error("align")
|
||||
}
|
||||
if !*o.PDFCellOpt.fill {
|
||||
t.Error("fill")
|
||||
}
|
||||
if *o.PDFCellOpt.link != 5 {
|
||||
t.Error("link")
|
||||
}
|
||||
if *o.PDFCellOpt.linkStr != "link" {
|
||||
t.Error("linkStr")
|
||||
}
|
||||
if *o.PDFCellOpt.fontNameOverride != FontTimes {
|
||||
t.Error("fontName")
|
||||
}
|
||||
if *o.PDFCellOpt.fontStyleOverride != Bold {
|
||||
t.Error("fontStyle")
|
||||
}
|
||||
if *o.PDFCellOpt.fontSizeOverride != 11 {
|
||||
t.Error("fontSize")
|
||||
}
|
||||
if *o.PDFCellOpt.extraLn != 2 {
|
||||
t.Error("extraLn")
|
||||
}
|
||||
if *o.PDFCellOpt.x != 3 {
|
||||
t.Error("x")
|
||||
}
|
||||
if !*o.PDFCellOpt.autoWidth {
|
||||
t.Error("autoWidth")
|
||||
}
|
||||
if *o.PDFCellOpt.autoWidthPaddingX != 1 {
|
||||
t.Error("autoWidthPaddingX")
|
||||
}
|
||||
if *o.PDFCellOpt.textColor != (PDFColor{R: 1, G: 2, B: 3}) {
|
||||
t.Error("textColor")
|
||||
}
|
||||
if *o.PDFCellOpt.borderColor != (PDFColor{R: 4, G: 5, B: 6}) {
|
||||
t.Error("borderColor")
|
||||
}
|
||||
if *o.PDFCellOpt.fillColor != (PDFColor{R: 7, G: 8, B: 9}) {
|
||||
t.Error("fillColor")
|
||||
}
|
||||
if o.PDFCellOpt.alphaOverride.V1 != 0.5 || o.PDFCellOpt.alphaOverride.V2 != BlendNormal {
|
||||
t.Error("alpha")
|
||||
}
|
||||
if !*o.PDFCellOpt.debug {
|
||||
t.Error("debug")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableCellStyleOptBoldItalic(t *testing.T) {
|
||||
if *NewTableCellStyleOpt().Bold().PDFCellOpt.fontStyleOverride != Bold {
|
||||
t.Error("Bold")
|
||||
}
|
||||
if *NewTableCellStyleOpt().Italic().PDFCellOpt.fontStyleOverride != Italic {
|
||||
t.Error("Italic")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableCellStyleOptHexColors(t *testing.T) {
|
||||
o := NewTableCellStyleOpt().
|
||||
TextColorHex(0x010203).
|
||||
BorderColorHex(0x040506).
|
||||
FillColorHex(0x070809)
|
||||
|
||||
if *o.PDFCellOpt.textColor != (PDFColor{R: 1, G: 2, B: 3}) {
|
||||
t.Error("text hex")
|
||||
}
|
||||
if *o.PDFCellOpt.borderColor != (PDFColor{R: 4, G: 5, B: 6}) {
|
||||
t.Error("border hex")
|
||||
}
|
||||
if *o.PDFCellOpt.fillColor != (PDFColor{R: 7, G: 8, B: 9}) {
|
||||
t.Error("fill hex")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableCellStyleOptIndividualFontSetters(t *testing.T) {
|
||||
o := NewTableCellStyleOpt().FontName(FontCourier).FontStyle(Italic).FontSize(9)
|
||||
if *o.PDFCellOpt.fontNameOverride != FontCourier {
|
||||
t.Error("FontName")
|
||||
}
|
||||
if *o.PDFCellOpt.fontStyleOverride != Italic {
|
||||
t.Error("FontStyle")
|
||||
}
|
||||
if *o.PDFCellOpt.fontSizeOverride != 9 {
|
||||
t.Error("FontSize")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableCalculateColumnsNumeric(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
tb := b.Table().
|
||||
Widths("30", "20", "40").
|
||||
AddRowDefaultStyle("a", "b", "c")
|
||||
|
||||
w := tb.calculateColumns()
|
||||
if len(w) != 3 {
|
||||
t.Fatalf("widths = %v, want 3", len(w))
|
||||
}
|
||||
if w[0] != 30 || w[1] != 20 || w[2] != 40 {
|
||||
t.Errorf("widths = %v, want [30, 20, 40]", w)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableCalculateColumnsFrSplit(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
b.SetMargins(PDFMargins{Left: 0, Top: 0, Right: 0})
|
||||
|
||||
tb := b.Table().
|
||||
PadX(0).
|
||||
Widths("1fr", "1fr").
|
||||
AddRowDefaultStyle("a", "b")
|
||||
|
||||
pageW := b.GetPageWidth()
|
||||
w := tb.calculateColumns()
|
||||
if len(w) != 2 {
|
||||
t.Fatalf("widths = %v, want 2", len(w))
|
||||
}
|
||||
|
||||
// fr columns are bounded by autoWidths (max content); since "a" and "b"
|
||||
// are very narrow strings, both columns get the same auto-bounded width.
|
||||
if math.Abs(w[0]-w[1]) > 0.01 {
|
||||
t.Errorf("expected fr split widths roughly equal, got %v and %v", w[0], w[1])
|
||||
}
|
||||
|
||||
// Total should not exceed available page width.
|
||||
if w[0]+w[1] > pageW+0.01 {
|
||||
t.Errorf("total width %v exceeds pageW %v", w[0]+w[1], pageW)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableCalculateColumnsAutoUsesMinWidth(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
style := *NewTableCellStyleOpt()
|
||||
mw := 50.0
|
||||
style.minWidth = &mw
|
||||
|
||||
tb := b.Table().
|
||||
Widths("auto").
|
||||
AddRowWithStyle(&style, "x")
|
||||
|
||||
w := tb.calculateColumns()
|
||||
if len(w) != 1 {
|
||||
t.Fatalf("widths = %v, want 1", len(w))
|
||||
}
|
||||
if w[0] < 50 {
|
||||
t.Errorf("width %v should respect minWidth=50", w[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestTableCalculateColumnsNoRows(t *testing.T) {
|
||||
b := newBuilderWithPage(t)
|
||||
tb := b.Table()
|
||||
w := tb.calculateColumns()
|
||||
if len(w) != 0 {
|
||||
t.Errorf("widths for empty table = %v, want []", w)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user