diff --git a/docs/assets/examples/autorow/v2/main_test.go b/docs/assets/examples/autorow/v2/main_test.go index 793c4452..baf88dcd 100644 --- a/docs/assets/examples/autorow/v2/main_test.go +++ b/docs/assets/examples/autorow/v2/main_test.go @@ -7,6 +7,8 @@ import ( ) func TestGetMaroto(t *testing.T) { + test.SetupTestDir(t) + // Act sut := GetMaroto() diff --git a/docs/assets/examples/imagegrid/v2/main_test.go b/docs/assets/examples/imagegrid/v2/main_test.go index 43c4802e..80db12fe 100644 --- a/docs/assets/examples/imagegrid/v2/main_test.go +++ b/docs/assets/examples/imagegrid/v2/main_test.go @@ -7,6 +7,7 @@ import ( ) func TestGetMaroto(t *testing.T) { + test.SetupTestDir(t) // Act sut := GetMaroto() diff --git a/internal/fixture/processorfixture.go b/internal/fixture/processorfixture.go new file mode 100644 index 00000000..19f704e7 --- /dev/null +++ b/internal/fixture/processorfixture.go @@ -0,0 +1,169 @@ +package fixture + +import ( + "time" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/buildermapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/codemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/colmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/imagemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/linemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/listmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/pagemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/rowmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/signaturemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/textmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" +) + +func MapperRow() *rowmapper.Row { + return &rowmapper.Row{ + Height: 0, + Cols: make([]mappers.Componentmapper, 0), + } +} + +func MapperPage() *pagemapper.Page { + return &pagemapper.Page{ + SourceKey: "template_page_1", + Rows: make([]mappers.OrderedComponents, 0), + } +} + +func MapperList() *listmapper.List { + return &listmapper.List{} +} + +func Barcode() *codemapper.Barcode { + return &codemapper.Barcode{Order: 1} +} + +func Matrixcode() *codemapper.Matrixcode { + return &codemapper.Matrixcode{Order: 1} +} + +func Qrcode() *codemapper.Qrcode { + return &codemapper.Qrcode{Order: 1} +} + +func Image() *imagemapper.Image { + return &imagemapper.Image{Order: 1} +} + +func Line() *linemapper.Line { + return &linemapper.Line{Order: 1} +} + +func Signature() *signaturemapper.Signature { + return &signaturemapper.Signature{Order: 1} +} + +func Text() *textmapper.Text { + return &textmapper.Text{Order: 1} +} + +func Metadata() *propsmapper.Metadata { + creation := time.Now() + return &propsmapper.Metadata{ + Author: &propsmapper.Utf8Text{Text: "Author", UTF8: true}, Creator: &propsmapper.Utf8Text{Text: "Creator", UTF8: true}, + Subject: &propsmapper.Utf8Text{Text: "Subject", UTF8: true}, Title: &propsmapper.Utf8Text{Text: "Title", UTF8: true}, + CreationDate: &creation, KeywordsStr: &propsmapper.Utf8Text{Text: "KeywordsStr", UTF8: true}, + } +} + +func BuilderProps() *buildermapper.Builder { + time, _ := time.Parse("2006-01-02 15:04:05", "2024-10-09 14:30:00") + return &buildermapper.Builder{ + Dimensions: &propsmapper.Dimensions{ + Width: 10.0, + Height: 10.0, + }, + Margins: &propsmapper.Margins{ + Left: 10.0, + Right: 10.0, + Top: 10.0, + Bottom: 10.0, + }, + SequentialMode: false, + ConcurrentMode: 10, + SequentialLowMemoryMode: -1, + Debug: true, + MaxGridSize: 10, + DefaultFont: &propsmapper.Font{ + Family: "Arial", + Style: "bold", + Size: 10, + Color: &propsmapper.Color{ + Red: 10, + Green: 100, + Blue: 150, + }, + }, + PageNumber: &propsmapper.PageNumber{ + Pattern: "pattern_test", + Place: "place_test", + Family: "family_test", + Style: "style_test", + Size: 10.0, + Color: &propsmapper.Color{ + Red: 10, + Green: 100, + Blue: 150, + }, + }, + CustomFonts: []*propsmapper.CustomFont{ + {Family: "family_test", Style: "style_test", File: "file_test"}, + {Family: "family_test2", Style: "style_test2", File: "file_test2"}, + }, + Protection: &propsmapper.Protection{ + Type: 4, + UserPassword: "senha123", + OwnerPassword: "senha123", + }, + Compression: true, + PageSize: "T", + Orientation: "vertical", + Metadata: &propsmapper.Metadata{ + Author: &propsmapper.Utf8Text{Text: "user_test", UTF8: true}, + Creator: &propsmapper.Utf8Text{Text: "user_test", UTF8: true}, + Subject: &propsmapper.Utf8Text{Text: "test", UTF8: true}, + Title: &propsmapper.Utf8Text{Text: "report", UTF8: true}, + CreationDate: &time, + KeywordsStr: &propsmapper.Utf8Text{Text: "test", UTF8: true}, + }, + DisableAutoPageBreak: true, + GenerationMode: "concurrent", + } +} + +func Row(sourceKeyRow, sourceKeyText string) *rowmapper.Row { + col := colmapper.Col{ + Size: 12, + Components: []mappers.OrderedComponents{}, + } + + return &rowmapper.Row{ + Height: 10, + SourceKey: sourceKeyRow, + Cols: []mappers.Componentmapper{&col}, + } +} + +func Page(sourceKeyPage, sourceKeyRow, sourceKeyText string) *pagemapper.Page { + col := colmapper.Col{ + Size: 12, + Components: []mappers.OrderedComponents{}, + } + + return &pagemapper.Page{ + SourceKey: sourceKeyPage, + Rows: []mappers.OrderedComponents{ + &rowmapper.Row{ + Height: 10, + SourceKey: sourceKeyRow, + Cols: []mappers.Componentmapper{&col}, + }, + }, + } +} diff --git a/internal/providers/gofpdf/builder.go b/internal/providers/gofpdf/builder.go index 6aa59f2e..11d821bb 100644 --- a/internal/providers/gofpdf/builder.go +++ b/internal/providers/gofpdf/builder.go @@ -25,8 +25,8 @@ type Dependencies struct { Cfg *entity.Config } -// Builder is the dependencies builder for gofpdf -type Builder interface { +// BuilderProvider is the dependencies builder for gofpdf +type BuilderProvider interface { Build(cfg *entity.Config, cache cache.Cache) *Dependencies } diff --git a/metricsdecorator_test.go b/metricsdecorator_test.go index ee66d78b..f2116b83 100644 --- a/metricsdecorator_test.go +++ b/metricsdecorator_test.go @@ -1,9 +1,10 @@ -package maroto +package maroto_test import ( "fmt" "testing" + "github.com/johnfercher/maroto/v2" "github.com/johnfercher/maroto/v2/pkg/core/entity" "github.com/johnfercher/maroto/v2/pkg/components/text" @@ -20,7 +21,7 @@ import ( func TestNewMetricsDecorator(t *testing.T) { // Act - sut := NewMetricsDecorator(nil) + sut := maroto.NewMetricsDecorator(nil) // Assert assert.NotNil(t, sut) @@ -37,7 +38,7 @@ func TestMetricsDecorator_AddPages(t *testing.T) { inner.EXPECT().AddPages(pg) inner.EXPECT().Generate().Return(docToReturn, nil) - sut := NewMetricsDecorator(inner) + sut := maroto.NewMetricsDecorator(inner) // Act sut.AddPages(pg) @@ -67,7 +68,7 @@ func TestMetricsDecorator_AddRow(t *testing.T) { inner.EXPECT().AddRow(10.0, col).Return(nil) inner.EXPECT().Generate().Return(docToReturn, nil) - sut := NewMetricsDecorator(inner) + sut := maroto.NewMetricsDecorator(inner) // Act sut.AddRow(10, col) @@ -97,7 +98,7 @@ func TestMetricsDecorator_AddRows(t *testing.T) { inner.EXPECT().AddRows(row) inner.EXPECT().Generate().Return(docToReturn, nil) - sut := NewMetricsDecorator(inner) + sut := maroto.NewMetricsDecorator(inner) // Act sut.AddRows(row) @@ -128,7 +129,7 @@ func TestMetricsDecorator_GetStructure(t *testing.T) { inner.EXPECT().GetStructure().Return(&node.Node[core.Structure]{}) inner.EXPECT().Generate().Return(docToReturn, nil) - sut := NewMetricsDecorator(inner) + sut := maroto.NewMetricsDecorator(inner) sut.AddRows(row) // Act @@ -156,7 +157,7 @@ func TestMetricsDecorator_FitlnCurrentPage(t *testing.T) { inner.EXPECT().FitlnCurrentPage(10.0).Return(true) inner.EXPECT().FitlnCurrentPage(20.0).Return(false) - sut := NewMetricsDecorator(inner) + sut := maroto.NewMetricsDecorator(inner) // Act & Assert assert.True(t, sut.FitlnCurrentPage(10)) @@ -171,7 +172,7 @@ func TestMetricsDecorator_GetCurrentConfig(t *testing.T) { inner := mocks.NewMaroto(t) inner.EXPECT().GetCurrentConfig().Return(cfgToReturn) - sut := NewMetricsDecorator(inner) + sut := maroto.NewMetricsDecorator(inner) // Act cfg := sut.GetCurrentConfig() @@ -188,7 +189,7 @@ func TestMetricsDecorator_RegisterHeader(t *testing.T) { inner.EXPECT().RegisterHeader(row).Return(nil) inner.EXPECT().Generate().Return(&core.Pdf{}, nil) - sut := NewMetricsDecorator(inner) + sut := maroto.NewMetricsDecorator(inner) // Act err := sut.RegisterHeader(row) @@ -214,7 +215,7 @@ func TestMetricsDecorator_RegisterFooter(t *testing.T) { inner.EXPECT().RegisterFooter(row).Return(nil) inner.EXPECT().Generate().Return(&core.Pdf{}, nil) - sut := NewMetricsDecorator(inner) + sut := maroto.NewMetricsDecorator(inner) // Act err := sut.RegisterFooter(row) diff --git a/mocks/AbstractFactoryMaps.go b/mocks/AbstractFactoryMaps.go new file mode 100644 index 00000000..6ab3df3c --- /dev/null +++ b/mocks/AbstractFactoryMaps.go @@ -0,0 +1,678 @@ +// Code generated by mockery v2.42.0. DO NOT EDIT. + +package mocks + +import ( + mappers "github.com/johnfercher/maroto/v2/pkg/processor/mappers" + mock "github.com/stretchr/testify/mock" +) + +// AbstractFactoryMaps is an autogenerated mock type for the AbstractFactoryMaps type +type AbstractFactoryMaps struct { + mock.Mock +} + +type AbstractFactoryMaps_Expecter struct { + mock *mock.Mock +} + +func (_m *AbstractFactoryMaps) EXPECT() *AbstractFactoryMaps_Expecter { + return &AbstractFactoryMaps_Expecter{mock: &_m.Mock} +} + +// NewBarcode provides a mock function with given fields: document +func (_m *AbstractFactoryMaps) NewBarcode(document interface{}) (mappers.OrderedComponents, error) { + ret := _m.Called(document) + + if len(ret) == 0 { + panic("no return value specified for NewBarcode") + } + + var r0 mappers.OrderedComponents + var r1 error + if rf, ok := ret.Get(0).(func(interface{}) (mappers.OrderedComponents, error)); ok { + return rf(document) + } + if rf, ok := ret.Get(0).(func(interface{}) mappers.OrderedComponents); ok { + r0 = rf(document) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(mappers.OrderedComponents) + } + } + + if rf, ok := ret.Get(1).(func(interface{}) error); ok { + r1 = rf(document) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AbstractFactoryMaps_NewBarcode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewBarcode' +type AbstractFactoryMaps_NewBarcode_Call struct { + *mock.Call +} + +// NewBarcode is a helper method to define mock.On call +// - document interface{} +func (_e *AbstractFactoryMaps_Expecter) NewBarcode(document interface{}) *AbstractFactoryMaps_NewBarcode_Call { + return &AbstractFactoryMaps_NewBarcode_Call{Call: _e.mock.On("NewBarcode", document)} +} + +func (_c *AbstractFactoryMaps_NewBarcode_Call) Run(run func(document interface{})) *AbstractFactoryMaps_NewBarcode_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{})) + }) + return _c +} + +func (_c *AbstractFactoryMaps_NewBarcode_Call) Return(_a0 mappers.OrderedComponents, _a1 error) *AbstractFactoryMaps_NewBarcode_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AbstractFactoryMaps_NewBarcode_Call) RunAndReturn(run func(interface{}) (mappers.OrderedComponents, error)) *AbstractFactoryMaps_NewBarcode_Call { + _c.Call.Return(run) + return _c +} + +// NewCol provides a mock function with given fields: document +func (_m *AbstractFactoryMaps) NewCol(document interface{}) (mappers.Componentmapper, error) { + ret := _m.Called(document) + + if len(ret) == 0 { + panic("no return value specified for NewCol") + } + + var r0 mappers.Componentmapper + var r1 error + if rf, ok := ret.Get(0).(func(interface{}) (mappers.Componentmapper, error)); ok { + return rf(document) + } + if rf, ok := ret.Get(0).(func(interface{}) mappers.Componentmapper); ok { + r0 = rf(document) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(mappers.Componentmapper) + } + } + + if rf, ok := ret.Get(1).(func(interface{}) error); ok { + r1 = rf(document) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AbstractFactoryMaps_NewCol_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewCol' +type AbstractFactoryMaps_NewCol_Call struct { + *mock.Call +} + +// NewCol is a helper method to define mock.On call +// - document interface{} +func (_e *AbstractFactoryMaps_Expecter) NewCol(document interface{}) *AbstractFactoryMaps_NewCol_Call { + return &AbstractFactoryMaps_NewCol_Call{Call: _e.mock.On("NewCol", document)} +} + +func (_c *AbstractFactoryMaps_NewCol_Call) Run(run func(document interface{})) *AbstractFactoryMaps_NewCol_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{})) + }) + return _c +} + +func (_c *AbstractFactoryMaps_NewCol_Call) Return(_a0 mappers.Componentmapper, _a1 error) *AbstractFactoryMaps_NewCol_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AbstractFactoryMaps_NewCol_Call) RunAndReturn(run func(interface{}) (mappers.Componentmapper, error)) *AbstractFactoryMaps_NewCol_Call { + _c.Call.Return(run) + return _c +} + +// NewImage provides a mock function with given fields: document +func (_m *AbstractFactoryMaps) NewImage(document interface{}) (mappers.OrderedComponents, error) { + ret := _m.Called(document) + + if len(ret) == 0 { + panic("no return value specified for NewImage") + } + + var r0 mappers.OrderedComponents + var r1 error + if rf, ok := ret.Get(0).(func(interface{}) (mappers.OrderedComponents, error)); ok { + return rf(document) + } + if rf, ok := ret.Get(0).(func(interface{}) mappers.OrderedComponents); ok { + r0 = rf(document) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(mappers.OrderedComponents) + } + } + + if rf, ok := ret.Get(1).(func(interface{}) error); ok { + r1 = rf(document) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AbstractFactoryMaps_NewImage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewImage' +type AbstractFactoryMaps_NewImage_Call struct { + *mock.Call +} + +// NewImage is a helper method to define mock.On call +// - document interface{} +func (_e *AbstractFactoryMaps_Expecter) NewImage(document interface{}) *AbstractFactoryMaps_NewImage_Call { + return &AbstractFactoryMaps_NewImage_Call{Call: _e.mock.On("NewImage", document)} +} + +func (_c *AbstractFactoryMaps_NewImage_Call) Run(run func(document interface{})) *AbstractFactoryMaps_NewImage_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{})) + }) + return _c +} + +func (_c *AbstractFactoryMaps_NewImage_Call) Return(_a0 mappers.OrderedComponents, _a1 error) *AbstractFactoryMaps_NewImage_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AbstractFactoryMaps_NewImage_Call) RunAndReturn(run func(interface{}) (mappers.OrderedComponents, error)) *AbstractFactoryMaps_NewImage_Call { + _c.Call.Return(run) + return _c +} + +// NewLine provides a mock function with given fields: document +func (_m *AbstractFactoryMaps) NewLine(document interface{}) (mappers.OrderedComponents, error) { + ret := _m.Called(document) + + if len(ret) == 0 { + panic("no return value specified for NewLine") + } + + var r0 mappers.OrderedComponents + var r1 error + if rf, ok := ret.Get(0).(func(interface{}) (mappers.OrderedComponents, error)); ok { + return rf(document) + } + if rf, ok := ret.Get(0).(func(interface{}) mappers.OrderedComponents); ok { + r0 = rf(document) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(mappers.OrderedComponents) + } + } + + if rf, ok := ret.Get(1).(func(interface{}) error); ok { + r1 = rf(document) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AbstractFactoryMaps_NewLine_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewLine' +type AbstractFactoryMaps_NewLine_Call struct { + *mock.Call +} + +// NewLine is a helper method to define mock.On call +// - document interface{} +func (_e *AbstractFactoryMaps_Expecter) NewLine(document interface{}) *AbstractFactoryMaps_NewLine_Call { + return &AbstractFactoryMaps_NewLine_Call{Call: _e.mock.On("NewLine", document)} +} + +func (_c *AbstractFactoryMaps_NewLine_Call) Run(run func(document interface{})) *AbstractFactoryMaps_NewLine_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{})) + }) + return _c +} + +func (_c *AbstractFactoryMaps_NewLine_Call) Return(_a0 mappers.OrderedComponents, _a1 error) *AbstractFactoryMaps_NewLine_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AbstractFactoryMaps_NewLine_Call) RunAndReturn(run func(interface{}) (mappers.OrderedComponents, error)) *AbstractFactoryMaps_NewLine_Call { + _c.Call.Return(run) + return _c +} + +// NewList provides a mock function with given fields: document, sourceKey, generate +func (_m *AbstractFactoryMaps) NewList(document interface{}, sourceKey string, generate mappers.GenerateComponent) (mappers.OrderedComponents, error) { + ret := _m.Called(document, sourceKey, generate) + + if len(ret) == 0 { + panic("no return value specified for NewList") + } + + var r0 mappers.OrderedComponents + var r1 error + if rf, ok := ret.Get(0).(func(interface{}, string, mappers.GenerateComponent) (mappers.OrderedComponents, error)); ok { + return rf(document, sourceKey, generate) + } + if rf, ok := ret.Get(0).(func(interface{}, string, mappers.GenerateComponent) mappers.OrderedComponents); ok { + r0 = rf(document, sourceKey, generate) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(mappers.OrderedComponents) + } + } + + if rf, ok := ret.Get(1).(func(interface{}, string, mappers.GenerateComponent) error); ok { + r1 = rf(document, sourceKey, generate) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AbstractFactoryMaps_NewList_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewList' +type AbstractFactoryMaps_NewList_Call struct { + *mock.Call +} + +// NewList is a helper method to define mock.On call +// - document interface{} +// - sourceKey string +// - generate mappers.GenerateComponent +func (_e *AbstractFactoryMaps_Expecter) NewList(document interface{}, sourceKey interface{}, generate interface{}) *AbstractFactoryMaps_NewList_Call { + return &AbstractFactoryMaps_NewList_Call{Call: _e.mock.On("NewList", document, sourceKey, generate)} +} + +func (_c *AbstractFactoryMaps_NewList_Call) Run(run func(document interface{}, sourceKey string, generate mappers.GenerateComponent)) *AbstractFactoryMaps_NewList_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{}), args[1].(string), args[2].(mappers.GenerateComponent)) + }) + return _c +} + +func (_c *AbstractFactoryMaps_NewList_Call) Return(_a0 mappers.OrderedComponents, _a1 error) *AbstractFactoryMaps_NewList_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AbstractFactoryMaps_NewList_Call) RunAndReturn(run func(interface{}, string, mappers.GenerateComponent) (mappers.OrderedComponents, error)) *AbstractFactoryMaps_NewList_Call { + _c.Call.Return(run) + return _c +} + +// NewMatrixcode provides a mock function with given fields: document +func (_m *AbstractFactoryMaps) NewMatrixcode(document interface{}) (mappers.OrderedComponents, error) { + ret := _m.Called(document) + + if len(ret) == 0 { + panic("no return value specified for NewMatrixcode") + } + + var r0 mappers.OrderedComponents + var r1 error + if rf, ok := ret.Get(0).(func(interface{}) (mappers.OrderedComponents, error)); ok { + return rf(document) + } + if rf, ok := ret.Get(0).(func(interface{}) mappers.OrderedComponents); ok { + r0 = rf(document) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(mappers.OrderedComponents) + } + } + + if rf, ok := ret.Get(1).(func(interface{}) error); ok { + r1 = rf(document) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AbstractFactoryMaps_NewMatrixcode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewMatrixcode' +type AbstractFactoryMaps_NewMatrixcode_Call struct { + *mock.Call +} + +// NewMatrixcode is a helper method to define mock.On call +// - document interface{} +func (_e *AbstractFactoryMaps_Expecter) NewMatrixcode(document interface{}) *AbstractFactoryMaps_NewMatrixcode_Call { + return &AbstractFactoryMaps_NewMatrixcode_Call{Call: _e.mock.On("NewMatrixcode", document)} +} + +func (_c *AbstractFactoryMaps_NewMatrixcode_Call) Run(run func(document interface{})) *AbstractFactoryMaps_NewMatrixcode_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{})) + }) + return _c +} + +func (_c *AbstractFactoryMaps_NewMatrixcode_Call) Return(_a0 mappers.OrderedComponents, _a1 error) *AbstractFactoryMaps_NewMatrixcode_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AbstractFactoryMaps_NewMatrixcode_Call) RunAndReturn(run func(interface{}) (mappers.OrderedComponents, error)) *AbstractFactoryMaps_NewMatrixcode_Call { + _c.Call.Return(run) + return _c +} + +// NewPage provides a mock function with given fields: document, sourceKey +func (_m *AbstractFactoryMaps) NewPage(document interface{}, sourceKey string) (mappers.OrderedComponents, error) { + ret := _m.Called(document, sourceKey) + + if len(ret) == 0 { + panic("no return value specified for NewPage") + } + + var r0 mappers.OrderedComponents + var r1 error + if rf, ok := ret.Get(0).(func(interface{}, string) (mappers.OrderedComponents, error)); ok { + return rf(document, sourceKey) + } + if rf, ok := ret.Get(0).(func(interface{}, string) mappers.OrderedComponents); ok { + r0 = rf(document, sourceKey) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(mappers.OrderedComponents) + } + } + + if rf, ok := ret.Get(1).(func(interface{}, string) error); ok { + r1 = rf(document, sourceKey) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AbstractFactoryMaps_NewPage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewPage' +type AbstractFactoryMaps_NewPage_Call struct { + *mock.Call +} + +// NewPage is a helper method to define mock.On call +// - document interface{} +// - sourceKey string +func (_e *AbstractFactoryMaps_Expecter) NewPage(document interface{}, sourceKey interface{}) *AbstractFactoryMaps_NewPage_Call { + return &AbstractFactoryMaps_NewPage_Call{Call: _e.mock.On("NewPage", document, sourceKey)} +} + +func (_c *AbstractFactoryMaps_NewPage_Call) Run(run func(document interface{}, sourceKey string)) *AbstractFactoryMaps_NewPage_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{}), args[1].(string)) + }) + return _c +} + +func (_c *AbstractFactoryMaps_NewPage_Call) Return(_a0 mappers.OrderedComponents, _a1 error) *AbstractFactoryMaps_NewPage_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AbstractFactoryMaps_NewPage_Call) RunAndReturn(run func(interface{}, string) (mappers.OrderedComponents, error)) *AbstractFactoryMaps_NewPage_Call { + _c.Call.Return(run) + return _c +} + +// NewQrcode provides a mock function with given fields: document +func (_m *AbstractFactoryMaps) NewQrcode(document interface{}) (mappers.OrderedComponents, error) { + ret := _m.Called(document) + + if len(ret) == 0 { + panic("no return value specified for NewQrcode") + } + + var r0 mappers.OrderedComponents + var r1 error + if rf, ok := ret.Get(0).(func(interface{}) (mappers.OrderedComponents, error)); ok { + return rf(document) + } + if rf, ok := ret.Get(0).(func(interface{}) mappers.OrderedComponents); ok { + r0 = rf(document) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(mappers.OrderedComponents) + } + } + + if rf, ok := ret.Get(1).(func(interface{}) error); ok { + r1 = rf(document) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AbstractFactoryMaps_NewQrcode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewQrcode' +type AbstractFactoryMaps_NewQrcode_Call struct { + *mock.Call +} + +// NewQrcode is a helper method to define mock.On call +// - document interface{} +func (_e *AbstractFactoryMaps_Expecter) NewQrcode(document interface{}) *AbstractFactoryMaps_NewQrcode_Call { + return &AbstractFactoryMaps_NewQrcode_Call{Call: _e.mock.On("NewQrcode", document)} +} + +func (_c *AbstractFactoryMaps_NewQrcode_Call) Run(run func(document interface{})) *AbstractFactoryMaps_NewQrcode_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{})) + }) + return _c +} + +func (_c *AbstractFactoryMaps_NewQrcode_Call) Return(_a0 mappers.OrderedComponents, _a1 error) *AbstractFactoryMaps_NewQrcode_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AbstractFactoryMaps_NewQrcode_Call) RunAndReturn(run func(interface{}) (mappers.OrderedComponents, error)) *AbstractFactoryMaps_NewQrcode_Call { + _c.Call.Return(run) + return _c +} + +// NewRow provides a mock function with given fields: document, sourceKey +func (_m *AbstractFactoryMaps) NewRow(document interface{}, sourceKey string) (mappers.OrderedComponents, error) { + ret := _m.Called(document, sourceKey) + + if len(ret) == 0 { + panic("no return value specified for NewRow") + } + + var r0 mappers.OrderedComponents + var r1 error + if rf, ok := ret.Get(0).(func(interface{}, string) (mappers.OrderedComponents, error)); ok { + return rf(document, sourceKey) + } + if rf, ok := ret.Get(0).(func(interface{}, string) mappers.OrderedComponents); ok { + r0 = rf(document, sourceKey) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(mappers.OrderedComponents) + } + } + + if rf, ok := ret.Get(1).(func(interface{}, string) error); ok { + r1 = rf(document, sourceKey) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AbstractFactoryMaps_NewRow_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewRow' +type AbstractFactoryMaps_NewRow_Call struct { + *mock.Call +} + +// NewRow is a helper method to define mock.On call +// - document interface{} +// - sourceKey string +func (_e *AbstractFactoryMaps_Expecter) NewRow(document interface{}, sourceKey interface{}) *AbstractFactoryMaps_NewRow_Call { + return &AbstractFactoryMaps_NewRow_Call{Call: _e.mock.On("NewRow", document, sourceKey)} +} + +func (_c *AbstractFactoryMaps_NewRow_Call) Run(run func(document interface{}, sourceKey string)) *AbstractFactoryMaps_NewRow_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{}), args[1].(string)) + }) + return _c +} + +func (_c *AbstractFactoryMaps_NewRow_Call) Return(_a0 mappers.OrderedComponents, _a1 error) *AbstractFactoryMaps_NewRow_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AbstractFactoryMaps_NewRow_Call) RunAndReturn(run func(interface{}, string) (mappers.OrderedComponents, error)) *AbstractFactoryMaps_NewRow_Call { + _c.Call.Return(run) + return _c +} + +// NewSignature provides a mock function with given fields: document +func (_m *AbstractFactoryMaps) NewSignature(document interface{}) (mappers.OrderedComponents, error) { + ret := _m.Called(document) + + if len(ret) == 0 { + panic("no return value specified for NewSignature") + } + + var r0 mappers.OrderedComponents + var r1 error + if rf, ok := ret.Get(0).(func(interface{}) (mappers.OrderedComponents, error)); ok { + return rf(document) + } + if rf, ok := ret.Get(0).(func(interface{}) mappers.OrderedComponents); ok { + r0 = rf(document) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(mappers.OrderedComponents) + } + } + + if rf, ok := ret.Get(1).(func(interface{}) error); ok { + r1 = rf(document) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AbstractFactoryMaps_NewSignature_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewSignature' +type AbstractFactoryMaps_NewSignature_Call struct { + *mock.Call +} + +// NewSignature is a helper method to define mock.On call +// - document interface{} +func (_e *AbstractFactoryMaps_Expecter) NewSignature(document interface{}) *AbstractFactoryMaps_NewSignature_Call { + return &AbstractFactoryMaps_NewSignature_Call{Call: _e.mock.On("NewSignature", document)} +} + +func (_c *AbstractFactoryMaps_NewSignature_Call) Run(run func(document interface{})) *AbstractFactoryMaps_NewSignature_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{})) + }) + return _c +} + +func (_c *AbstractFactoryMaps_NewSignature_Call) Return(_a0 mappers.OrderedComponents, _a1 error) *AbstractFactoryMaps_NewSignature_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AbstractFactoryMaps_NewSignature_Call) RunAndReturn(run func(interface{}) (mappers.OrderedComponents, error)) *AbstractFactoryMaps_NewSignature_Call { + _c.Call.Return(run) + return _c +} + +// NewText provides a mock function with given fields: document +func (_m *AbstractFactoryMaps) NewText(document interface{}) (mappers.OrderedComponents, error) { + ret := _m.Called(document) + + if len(ret) == 0 { + panic("no return value specified for NewText") + } + + var r0 mappers.OrderedComponents + var r1 error + if rf, ok := ret.Get(0).(func(interface{}) (mappers.OrderedComponents, error)); ok { + return rf(document) + } + if rf, ok := ret.Get(0).(func(interface{}) mappers.OrderedComponents); ok { + r0 = rf(document) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(mappers.OrderedComponents) + } + } + + if rf, ok := ret.Get(1).(func(interface{}) error); ok { + r1 = rf(document) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AbstractFactoryMaps_NewText_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NewText' +type AbstractFactoryMaps_NewText_Call struct { + *mock.Call +} + +// NewText is a helper method to define mock.On call +// - document interface{} +func (_e *AbstractFactoryMaps_Expecter) NewText(document interface{}) *AbstractFactoryMaps_NewText_Call { + return &AbstractFactoryMaps_NewText_Call{Call: _e.mock.On("NewText", document)} +} + +func (_c *AbstractFactoryMaps_NewText_Call) Run(run func(document interface{})) *AbstractFactoryMaps_NewText_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{})) + }) + return _c +} + +func (_c *AbstractFactoryMaps_NewText_Call) Return(_a0 mappers.OrderedComponents, _a1 error) *AbstractFactoryMaps_NewText_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *AbstractFactoryMaps_NewText_Call) RunAndReturn(run func(interface{}) (mappers.OrderedComponents, error)) *AbstractFactoryMaps_NewText_Call { + _c.Call.Return(run) + return _c +} + +// NewAbstractFactoryMaps creates a new instance of AbstractFactoryMaps. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewAbstractFactoryMaps(t interface { + mock.TestingT + Cleanup(func()) +}, +) *AbstractFactoryMaps { + mock := &AbstractFactoryMaps{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/Builder.go b/mocks/Builder.go index 883f7968..2cbe240a 100644 --- a/mocks/Builder.go +++ b/mocks/Builder.go @@ -3,12 +3,22 @@ package mocks import ( - cache "github.com/johnfercher/maroto/v2/internal/cache" + config "github.com/johnfercher/maroto/v2/pkg/config" entity "github.com/johnfercher/maroto/v2/pkg/core/entity" - gofpdf "github.com/johnfercher/maroto/v2/internal/providers/gofpdf" + extension "github.com/johnfercher/maroto/v2/pkg/consts/extension" mock "github.com/stretchr/testify/mock" + + orientation "github.com/johnfercher/maroto/v2/pkg/consts/orientation" + + pagesize "github.com/johnfercher/maroto/v2/pkg/consts/pagesize" + + props "github.com/johnfercher/maroto/v2/pkg/props" + + protection "github.com/johnfercher/maroto/v2/pkg/consts/protection" + + time "time" ) // Builder is an autogenerated mock type for the Builder type @@ -24,20 +34,20 @@ func (_m *Builder) EXPECT() *Builder_Expecter { return &Builder_Expecter{mock: &_m.Mock} } -// Build provides a mock function with given fields: cfg, _a1 -func (_m *Builder) Build(cfg *entity.Config, _a1 cache.Cache) *gofpdf.Dependencies { - ret := _m.Called(cfg, _a1) +// Build provides a mock function with given fields: +func (_m *Builder) Build() *entity.Config { + ret := _m.Called() if len(ret) == 0 { panic("no return value specified for Build") } - var r0 *gofpdf.Dependencies - if rf, ok := ret.Get(0).(func(*entity.Config, cache.Cache) *gofpdf.Dependencies); ok { - r0 = rf(cfg, _a1) + var r0 *entity.Config + if rf, ok := ret.Get(0).(func() *entity.Config); ok { + r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*gofpdf.Dependencies) + r0 = ret.Get(0).(*entity.Config) } } @@ -50,25 +60,1244 @@ type Builder_Build_Call struct { } // Build is a helper method to define mock.On call -// - cfg *entity.Config -// - _a1 cache.Cache -func (_e *Builder_Expecter) Build(cfg interface{}, _a1 interface{}) *Builder_Build_Call { - return &Builder_Build_Call{Call: _e.mock.On("Build", cfg, _a1)} +func (_e *Builder_Expecter) Build() *Builder_Build_Call { + return &Builder_Build_Call{Call: _e.mock.On("Build")} +} + +func (_c *Builder_Build_Call) Run(run func()) *Builder_Build_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Builder_Build_Call) Return(_a0 *entity.Config) *Builder_Build_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_Build_Call) RunAndReturn(run func() *entity.Config) *Builder_Build_Call { + _c.Call.Return(run) + return _c +} + +// WithAuthor provides a mock function with given fields: author, isUTF8 +func (_m *Builder) WithAuthor(author string, isUTF8 bool) config.Builder { + ret := _m.Called(author, isUTF8) + + if len(ret) == 0 { + panic("no return value specified for WithAuthor") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(string, bool) config.Builder); ok { + r0 = rf(author, isUTF8) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithAuthor_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithAuthor' +type Builder_WithAuthor_Call struct { + *mock.Call +} + +// WithAuthor is a helper method to define mock.On call +// - author string +// - isUTF8 bool +func (_e *Builder_Expecter) WithAuthor(author interface{}, isUTF8 interface{}) *Builder_WithAuthor_Call { + return &Builder_WithAuthor_Call{Call: _e.mock.On("WithAuthor", author, isUTF8)} +} + +func (_c *Builder_WithAuthor_Call) Run(run func(author string, isUTF8 bool)) *Builder_WithAuthor_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(bool)) + }) + return _c +} + +func (_c *Builder_WithAuthor_Call) Return(_a0 config.Builder) *Builder_WithAuthor_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithAuthor_Call) RunAndReturn(run func(string, bool) config.Builder) *Builder_WithAuthor_Call { + _c.Call.Return(run) + return _c +} + +// WithBackgroundImage provides a mock function with given fields: _a0, _a1 +func (_m *Builder) WithBackgroundImage(_a0 []byte, _a1 extension.Type) config.Builder { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for WithBackgroundImage") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func([]byte, extension.Type) config.Builder); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithBackgroundImage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithBackgroundImage' +type Builder_WithBackgroundImage_Call struct { + *mock.Call +} + +// WithBackgroundImage is a helper method to define mock.On call +// - _a0 []byte +// - _a1 extension.Type +func (_e *Builder_Expecter) WithBackgroundImage(_a0 interface{}, _a1 interface{}) *Builder_WithBackgroundImage_Call { + return &Builder_WithBackgroundImage_Call{Call: _e.mock.On("WithBackgroundImage", _a0, _a1)} +} + +func (_c *Builder_WithBackgroundImage_Call) Run(run func(_a0 []byte, _a1 extension.Type)) *Builder_WithBackgroundImage_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].([]byte), args[1].(extension.Type)) + }) + return _c +} + +func (_c *Builder_WithBackgroundImage_Call) Return(_a0 config.Builder) *Builder_WithBackgroundImage_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithBackgroundImage_Call) RunAndReturn(run func([]byte, extension.Type) config.Builder) *Builder_WithBackgroundImage_Call { + _c.Call.Return(run) + return _c +} + +// WithBottomMargin provides a mock function with given fields: bottom +func (_m *Builder) WithBottomMargin(bottom float64) config.Builder { + ret := _m.Called(bottom) + + if len(ret) == 0 { + panic("no return value specified for WithBottomMargin") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(float64) config.Builder); ok { + r0 = rf(bottom) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithBottomMargin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithBottomMargin' +type Builder_WithBottomMargin_Call struct { + *mock.Call +} + +// WithBottomMargin is a helper method to define mock.On call +// - bottom float64 +func (_e *Builder_Expecter) WithBottomMargin(bottom interface{}) *Builder_WithBottomMargin_Call { + return &Builder_WithBottomMargin_Call{Call: _e.mock.On("WithBottomMargin", bottom)} +} + +func (_c *Builder_WithBottomMargin_Call) Run(run func(bottom float64)) *Builder_WithBottomMargin_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(float64)) + }) + return _c +} + +func (_c *Builder_WithBottomMargin_Call) Return(_a0 config.Builder) *Builder_WithBottomMargin_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithBottomMargin_Call) RunAndReturn(run func(float64) config.Builder) *Builder_WithBottomMargin_Call { + _c.Call.Return(run) + return _c +} + +// WithCompression provides a mock function with given fields: compression +func (_m *Builder) WithCompression(compression bool) config.Builder { + ret := _m.Called(compression) + + if len(ret) == 0 { + panic("no return value specified for WithCompression") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(bool) config.Builder); ok { + r0 = rf(compression) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithCompression_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithCompression' +type Builder_WithCompression_Call struct { + *mock.Call +} + +// WithCompression is a helper method to define mock.On call +// - compression bool +func (_e *Builder_Expecter) WithCompression(compression interface{}) *Builder_WithCompression_Call { + return &Builder_WithCompression_Call{Call: _e.mock.On("WithCompression", compression)} +} + +func (_c *Builder_WithCompression_Call) Run(run func(compression bool)) *Builder_WithCompression_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(bool)) + }) + return _c +} + +func (_c *Builder_WithCompression_Call) Return(_a0 config.Builder) *Builder_WithCompression_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithCompression_Call) RunAndReturn(run func(bool) config.Builder) *Builder_WithCompression_Call { + _c.Call.Return(run) + return _c +} + +// WithConcurrentMode provides a mock function with given fields: chunkWorkers +func (_m *Builder) WithConcurrentMode(chunkWorkers int) config.Builder { + ret := _m.Called(chunkWorkers) + + if len(ret) == 0 { + panic("no return value specified for WithConcurrentMode") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(int) config.Builder); ok { + r0 = rf(chunkWorkers) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithConcurrentMode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithConcurrentMode' +type Builder_WithConcurrentMode_Call struct { + *mock.Call +} + +// WithConcurrentMode is a helper method to define mock.On call +// - chunkWorkers int +func (_e *Builder_Expecter) WithConcurrentMode(chunkWorkers interface{}) *Builder_WithConcurrentMode_Call { + return &Builder_WithConcurrentMode_Call{Call: _e.mock.On("WithConcurrentMode", chunkWorkers)} +} + +func (_c *Builder_WithConcurrentMode_Call) Run(run func(chunkWorkers int)) *Builder_WithConcurrentMode_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int)) + }) + return _c +} + +func (_c *Builder_WithConcurrentMode_Call) Return(_a0 config.Builder) *Builder_WithConcurrentMode_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithConcurrentMode_Call) RunAndReturn(run func(int) config.Builder) *Builder_WithConcurrentMode_Call { + _c.Call.Return(run) + return _c +} + +// WithCreationDate provides a mock function with given fields: _a0 +func (_m *Builder) WithCreationDate(_a0 time.Time) config.Builder { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for WithCreationDate") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(time.Time) config.Builder); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithCreationDate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithCreationDate' +type Builder_WithCreationDate_Call struct { + *mock.Call +} + +// WithCreationDate is a helper method to define mock.On call +// - _a0 time.Time +func (_e *Builder_Expecter) WithCreationDate(_a0 interface{}) *Builder_WithCreationDate_Call { + return &Builder_WithCreationDate_Call{Call: _e.mock.On("WithCreationDate", _a0)} +} + +func (_c *Builder_WithCreationDate_Call) Run(run func(_a0 time.Time)) *Builder_WithCreationDate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(time.Time)) + }) + return _c +} + +func (_c *Builder_WithCreationDate_Call) Return(_a0 config.Builder) *Builder_WithCreationDate_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithCreationDate_Call) RunAndReturn(run func(time.Time) config.Builder) *Builder_WithCreationDate_Call { + _c.Call.Return(run) + return _c +} + +// WithCreator provides a mock function with given fields: creator, isUTF8 +func (_m *Builder) WithCreator(creator string, isUTF8 bool) config.Builder { + ret := _m.Called(creator, isUTF8) + + if len(ret) == 0 { + panic("no return value specified for WithCreator") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(string, bool) config.Builder); ok { + r0 = rf(creator, isUTF8) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithCreator_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithCreator' +type Builder_WithCreator_Call struct { + *mock.Call +} + +// WithCreator is a helper method to define mock.On call +// - creator string +// - isUTF8 bool +func (_e *Builder_Expecter) WithCreator(creator interface{}, isUTF8 interface{}) *Builder_WithCreator_Call { + return &Builder_WithCreator_Call{Call: _e.mock.On("WithCreator", creator, isUTF8)} +} + +func (_c *Builder_WithCreator_Call) Run(run func(creator string, isUTF8 bool)) *Builder_WithCreator_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(bool)) + }) + return _c +} + +func (_c *Builder_WithCreator_Call) Return(_a0 config.Builder) *Builder_WithCreator_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithCreator_Call) RunAndReturn(run func(string, bool) config.Builder) *Builder_WithCreator_Call { + _c.Call.Return(run) + return _c +} + +// WithCustomFonts provides a mock function with given fields: _a0 +func (_m *Builder) WithCustomFonts(_a0 []*entity.CustomFont) config.Builder { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for WithCustomFonts") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func([]*entity.CustomFont) config.Builder); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithCustomFonts_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithCustomFonts' +type Builder_WithCustomFonts_Call struct { + *mock.Call +} + +// WithCustomFonts is a helper method to define mock.On call +// - _a0 []*entity.CustomFont +func (_e *Builder_Expecter) WithCustomFonts(_a0 interface{}) *Builder_WithCustomFonts_Call { + return &Builder_WithCustomFonts_Call{Call: _e.mock.On("WithCustomFonts", _a0)} +} + +func (_c *Builder_WithCustomFonts_Call) Run(run func(_a0 []*entity.CustomFont)) *Builder_WithCustomFonts_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].([]*entity.CustomFont)) + }) + return _c +} + +func (_c *Builder_WithCustomFonts_Call) Return(_a0 config.Builder) *Builder_WithCustomFonts_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithCustomFonts_Call) RunAndReturn(run func([]*entity.CustomFont) config.Builder) *Builder_WithCustomFonts_Call { + _c.Call.Return(run) + return _c +} + +// WithDebug provides a mock function with given fields: on +func (_m *Builder) WithDebug(on bool) config.Builder { + ret := _m.Called(on) + + if len(ret) == 0 { + panic("no return value specified for WithDebug") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(bool) config.Builder); ok { + r0 = rf(on) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithDebug_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithDebug' +type Builder_WithDebug_Call struct { + *mock.Call +} + +// WithDebug is a helper method to define mock.On call +// - on bool +func (_e *Builder_Expecter) WithDebug(on interface{}) *Builder_WithDebug_Call { + return &Builder_WithDebug_Call{Call: _e.mock.On("WithDebug", on)} +} + +func (_c *Builder_WithDebug_Call) Run(run func(on bool)) *Builder_WithDebug_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(bool)) + }) + return _c +} + +func (_c *Builder_WithDebug_Call) Return(_a0 config.Builder) *Builder_WithDebug_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithDebug_Call) RunAndReturn(run func(bool) config.Builder) *Builder_WithDebug_Call { + _c.Call.Return(run) + return _c +} + +// WithDefaultFont provides a mock function with given fields: font +func (_m *Builder) WithDefaultFont(font *props.Font) config.Builder { + ret := _m.Called(font) + + if len(ret) == 0 { + panic("no return value specified for WithDefaultFont") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(*props.Font) config.Builder); ok { + r0 = rf(font) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithDefaultFont_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithDefaultFont' +type Builder_WithDefaultFont_Call struct { + *mock.Call +} + +// WithDefaultFont is a helper method to define mock.On call +// - font *props.Font +func (_e *Builder_Expecter) WithDefaultFont(font interface{}) *Builder_WithDefaultFont_Call { + return &Builder_WithDefaultFont_Call{Call: _e.mock.On("WithDefaultFont", font)} +} + +func (_c *Builder_WithDefaultFont_Call) Run(run func(font *props.Font)) *Builder_WithDefaultFont_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*props.Font)) + }) + return _c +} + +func (_c *Builder_WithDefaultFont_Call) Return(_a0 config.Builder) *Builder_WithDefaultFont_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithDefaultFont_Call) RunAndReturn(run func(*props.Font) config.Builder) *Builder_WithDefaultFont_Call { + _c.Call.Return(run) + return _c +} + +// WithDimensions provides a mock function with given fields: width, height +func (_m *Builder) WithDimensions(width float64, height float64) config.Builder { + ret := _m.Called(width, height) + + if len(ret) == 0 { + panic("no return value specified for WithDimensions") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(float64, float64) config.Builder); ok { + r0 = rf(width, height) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithDimensions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithDimensions' +type Builder_WithDimensions_Call struct { + *mock.Call +} + +// WithDimensions is a helper method to define mock.On call +// - width float64 +// - height float64 +func (_e *Builder_Expecter) WithDimensions(width interface{}, height interface{}) *Builder_WithDimensions_Call { + return &Builder_WithDimensions_Call{Call: _e.mock.On("WithDimensions", width, height)} +} + +func (_c *Builder_WithDimensions_Call) Run(run func(width float64, height float64)) *Builder_WithDimensions_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(float64), args[1].(float64)) + }) + return _c +} + +func (_c *Builder_WithDimensions_Call) Return(_a0 config.Builder) *Builder_WithDimensions_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithDimensions_Call) RunAndReturn(run func(float64, float64) config.Builder) *Builder_WithDimensions_Call { + _c.Call.Return(run) + return _c +} + +// WithDisableAutoPageBreak provides a mock function with given fields: disabled +func (_m *Builder) WithDisableAutoPageBreak(disabled bool) config.Builder { + ret := _m.Called(disabled) + + if len(ret) == 0 { + panic("no return value specified for WithDisableAutoPageBreak") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(bool) config.Builder); ok { + r0 = rf(disabled) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithDisableAutoPageBreak_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithDisableAutoPageBreak' +type Builder_WithDisableAutoPageBreak_Call struct { + *mock.Call +} + +// WithDisableAutoPageBreak is a helper method to define mock.On call +// - disabled bool +func (_e *Builder_Expecter) WithDisableAutoPageBreak(disabled interface{}) *Builder_WithDisableAutoPageBreak_Call { + return &Builder_WithDisableAutoPageBreak_Call{Call: _e.mock.On("WithDisableAutoPageBreak", disabled)} +} + +func (_c *Builder_WithDisableAutoPageBreak_Call) Run(run func(disabled bool)) *Builder_WithDisableAutoPageBreak_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(bool)) + }) + return _c +} + +func (_c *Builder_WithDisableAutoPageBreak_Call) Return(_a0 config.Builder) *Builder_WithDisableAutoPageBreak_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithDisableAutoPageBreak_Call) RunAndReturn(run func(bool) config.Builder) *Builder_WithDisableAutoPageBreak_Call { + _c.Call.Return(run) + return _c +} + +// WithKeywords provides a mock function with given fields: keywordsStr, isUTF8 +func (_m *Builder) WithKeywords(keywordsStr string, isUTF8 bool) config.Builder { + ret := _m.Called(keywordsStr, isUTF8) + + if len(ret) == 0 { + panic("no return value specified for WithKeywords") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(string, bool) config.Builder); ok { + r0 = rf(keywordsStr, isUTF8) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithKeywords_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithKeywords' +type Builder_WithKeywords_Call struct { + *mock.Call +} + +// WithKeywords is a helper method to define mock.On call +// - keywordsStr string +// - isUTF8 bool +func (_e *Builder_Expecter) WithKeywords(keywordsStr interface{}, isUTF8 interface{}) *Builder_WithKeywords_Call { + return &Builder_WithKeywords_Call{Call: _e.mock.On("WithKeywords", keywordsStr, isUTF8)} +} + +func (_c *Builder_WithKeywords_Call) Run(run func(keywordsStr string, isUTF8 bool)) *Builder_WithKeywords_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(bool)) + }) + return _c +} + +func (_c *Builder_WithKeywords_Call) Return(_a0 config.Builder) *Builder_WithKeywords_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithKeywords_Call) RunAndReturn(run func(string, bool) config.Builder) *Builder_WithKeywords_Call { + _c.Call.Return(run) + return _c +} + +// WithLeftMargin provides a mock function with given fields: left +func (_m *Builder) WithLeftMargin(left float64) config.Builder { + ret := _m.Called(left) + + if len(ret) == 0 { + panic("no return value specified for WithLeftMargin") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(float64) config.Builder); ok { + r0 = rf(left) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithLeftMargin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithLeftMargin' +type Builder_WithLeftMargin_Call struct { + *mock.Call +} + +// WithLeftMargin is a helper method to define mock.On call +// - left float64 +func (_e *Builder_Expecter) WithLeftMargin(left interface{}) *Builder_WithLeftMargin_Call { + return &Builder_WithLeftMargin_Call{Call: _e.mock.On("WithLeftMargin", left)} +} + +func (_c *Builder_WithLeftMargin_Call) Run(run func(left float64)) *Builder_WithLeftMargin_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(float64)) + }) + return _c +} + +func (_c *Builder_WithLeftMargin_Call) Return(_a0 config.Builder) *Builder_WithLeftMargin_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithLeftMargin_Call) RunAndReturn(run func(float64) config.Builder) *Builder_WithLeftMargin_Call { + _c.Call.Return(run) + return _c +} + +// WithMaxGridSize provides a mock function with given fields: maxGridSize +func (_m *Builder) WithMaxGridSize(maxGridSize int) config.Builder { + ret := _m.Called(maxGridSize) + + if len(ret) == 0 { + panic("no return value specified for WithMaxGridSize") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(int) config.Builder); ok { + r0 = rf(maxGridSize) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithMaxGridSize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithMaxGridSize' +type Builder_WithMaxGridSize_Call struct { + *mock.Call +} + +// WithMaxGridSize is a helper method to define mock.On call +// - maxGridSize int +func (_e *Builder_Expecter) WithMaxGridSize(maxGridSize interface{}) *Builder_WithMaxGridSize_Call { + return &Builder_WithMaxGridSize_Call{Call: _e.mock.On("WithMaxGridSize", maxGridSize)} +} + +func (_c *Builder_WithMaxGridSize_Call) Run(run func(maxGridSize int)) *Builder_WithMaxGridSize_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int)) + }) + return _c +} + +func (_c *Builder_WithMaxGridSize_Call) Return(_a0 config.Builder) *Builder_WithMaxGridSize_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithMaxGridSize_Call) RunAndReturn(run func(int) config.Builder) *Builder_WithMaxGridSize_Call { + _c.Call.Return(run) + return _c +} + +// WithOrientation provides a mock function with given fields: _a0 +func (_m *Builder) WithOrientation(_a0 orientation.Type) config.Builder { + ret := _m.Called(_a0) + + if len(ret) == 0 { + panic("no return value specified for WithOrientation") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(orientation.Type) config.Builder); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithOrientation_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithOrientation' +type Builder_WithOrientation_Call struct { + *mock.Call +} + +// WithOrientation is a helper method to define mock.On call +// - _a0 orientation.Type +func (_e *Builder_Expecter) WithOrientation(_a0 interface{}) *Builder_WithOrientation_Call { + return &Builder_WithOrientation_Call{Call: _e.mock.On("WithOrientation", _a0)} +} + +func (_c *Builder_WithOrientation_Call) Run(run func(_a0 orientation.Type)) *Builder_WithOrientation_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(orientation.Type)) + }) + return _c +} + +func (_c *Builder_WithOrientation_Call) Return(_a0 config.Builder) *Builder_WithOrientation_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithOrientation_Call) RunAndReturn(run func(orientation.Type) config.Builder) *Builder_WithOrientation_Call { + _c.Call.Return(run) + return _c +} + +// WithPageNumber provides a mock function with given fields: pageNumber +func (_m *Builder) WithPageNumber(pageNumber ...props.PageNumber) config.Builder { + _va := make([]interface{}, len(pageNumber)) + for _i := range pageNumber { + _va[_i] = pageNumber[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for WithPageNumber") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(...props.PageNumber) config.Builder); ok { + r0 = rf(pageNumber...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithPageNumber_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithPageNumber' +type Builder_WithPageNumber_Call struct { + *mock.Call +} + +// WithPageNumber is a helper method to define mock.On call +// - pageNumber ...props.PageNumber +func (_e *Builder_Expecter) WithPageNumber(pageNumber ...interface{}) *Builder_WithPageNumber_Call { + return &Builder_WithPageNumber_Call{Call: _e.mock.On("WithPageNumber", + append([]interface{}{}, pageNumber...)...)} +} + +func (_c *Builder_WithPageNumber_Call) Run(run func(pageNumber ...props.PageNumber)) *Builder_WithPageNumber_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]props.PageNumber, len(args)-0) + for i, a := range args[0:] { + if a != nil { + variadicArgs[i] = a.(props.PageNumber) + } + } + run(variadicArgs...) + }) + return _c +} + +func (_c *Builder_WithPageNumber_Call) Return(_a0 config.Builder) *Builder_WithPageNumber_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithPageNumber_Call) RunAndReturn(run func(...props.PageNumber) config.Builder) *Builder_WithPageNumber_Call { + _c.Call.Return(run) + return _c +} + +// WithPageSize provides a mock function with given fields: size +func (_m *Builder) WithPageSize(size pagesize.Type) config.Builder { + ret := _m.Called(size) + + if len(ret) == 0 { + panic("no return value specified for WithPageSize") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(pagesize.Type) config.Builder); ok { + r0 = rf(size) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithPageSize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithPageSize' +type Builder_WithPageSize_Call struct { + *mock.Call +} + +// WithPageSize is a helper method to define mock.On call +// - size pagesize.Type +func (_e *Builder_Expecter) WithPageSize(size interface{}) *Builder_WithPageSize_Call { + return &Builder_WithPageSize_Call{Call: _e.mock.On("WithPageSize", size)} +} + +func (_c *Builder_WithPageSize_Call) Run(run func(size pagesize.Type)) *Builder_WithPageSize_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(pagesize.Type)) + }) + return _c +} + +func (_c *Builder_WithPageSize_Call) Return(_a0 config.Builder) *Builder_WithPageSize_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithPageSize_Call) RunAndReturn(run func(pagesize.Type) config.Builder) *Builder_WithPageSize_Call { + _c.Call.Return(run) + return _c +} + +// WithProtection provides a mock function with given fields: protectionType, userPassword, ownerPassword +func (_m *Builder) WithProtection(protectionType protection.Type, userPassword string, ownerPassword string) config.Builder { + ret := _m.Called(protectionType, userPassword, ownerPassword) + + if len(ret) == 0 { + panic("no return value specified for WithProtection") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(protection.Type, string, string) config.Builder); ok { + r0 = rf(protectionType, userPassword, ownerPassword) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithProtection_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithProtection' +type Builder_WithProtection_Call struct { + *mock.Call +} + +// WithProtection is a helper method to define mock.On call +// - protectionType protection.Type +// - userPassword string +// - ownerPassword string +func (_e *Builder_Expecter) WithProtection(protectionType interface{}, userPassword interface{}, ownerPassword interface{}) *Builder_WithProtection_Call { + return &Builder_WithProtection_Call{Call: _e.mock.On("WithProtection", protectionType, userPassword, ownerPassword)} +} + +func (_c *Builder_WithProtection_Call) Run(run func(protectionType protection.Type, userPassword string, ownerPassword string)) *Builder_WithProtection_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(protection.Type), args[1].(string), args[2].(string)) + }) + return _c +} + +func (_c *Builder_WithProtection_Call) Return(_a0 config.Builder) *Builder_WithProtection_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithProtection_Call) RunAndReturn(run func(protection.Type, string, string) config.Builder) *Builder_WithProtection_Call { + _c.Call.Return(run) + return _c +} + +// WithRightMargin provides a mock function with given fields: right +func (_m *Builder) WithRightMargin(right float64) config.Builder { + ret := _m.Called(right) + + if len(ret) == 0 { + panic("no return value specified for WithRightMargin") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(float64) config.Builder); ok { + r0 = rf(right) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithRightMargin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithRightMargin' +type Builder_WithRightMargin_Call struct { + *mock.Call +} + +// WithRightMargin is a helper method to define mock.On call +// - right float64 +func (_e *Builder_Expecter) WithRightMargin(right interface{}) *Builder_WithRightMargin_Call { + return &Builder_WithRightMargin_Call{Call: _e.mock.On("WithRightMargin", right)} +} + +func (_c *Builder_WithRightMargin_Call) Run(run func(right float64)) *Builder_WithRightMargin_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(float64)) + }) + return _c +} + +func (_c *Builder_WithRightMargin_Call) Return(_a0 config.Builder) *Builder_WithRightMargin_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithRightMargin_Call) RunAndReturn(run func(float64) config.Builder) *Builder_WithRightMargin_Call { + _c.Call.Return(run) + return _c +} + +// WithSequentialLowMemoryMode provides a mock function with given fields: chunkWorkers +func (_m *Builder) WithSequentialLowMemoryMode(chunkWorkers int) config.Builder { + ret := _m.Called(chunkWorkers) + + if len(ret) == 0 { + panic("no return value specified for WithSequentialLowMemoryMode") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(int) config.Builder); ok { + r0 = rf(chunkWorkers) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithSequentialLowMemoryMode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithSequentialLowMemoryMode' +type Builder_WithSequentialLowMemoryMode_Call struct { + *mock.Call +} + +// WithSequentialLowMemoryMode is a helper method to define mock.On call +// - chunkWorkers int +func (_e *Builder_Expecter) WithSequentialLowMemoryMode(chunkWorkers interface{}) *Builder_WithSequentialLowMemoryMode_Call { + return &Builder_WithSequentialLowMemoryMode_Call{Call: _e.mock.On("WithSequentialLowMemoryMode", chunkWorkers)} +} + +func (_c *Builder_WithSequentialLowMemoryMode_Call) Run(run func(chunkWorkers int)) *Builder_WithSequentialLowMemoryMode_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(int)) + }) + return _c +} + +func (_c *Builder_WithSequentialLowMemoryMode_Call) Return(_a0 config.Builder) *Builder_WithSequentialLowMemoryMode_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithSequentialLowMemoryMode_Call) RunAndReturn(run func(int) config.Builder) *Builder_WithSequentialLowMemoryMode_Call { + _c.Call.Return(run) + return _c +} + +// WithSequentialMode provides a mock function with given fields: +func (_m *Builder) WithSequentialMode() config.Builder { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for WithSequentialMode") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func() config.Builder); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithSequentialMode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithSequentialMode' +type Builder_WithSequentialMode_Call struct { + *mock.Call +} + +// WithSequentialMode is a helper method to define mock.On call +func (_e *Builder_Expecter) WithSequentialMode() *Builder_WithSequentialMode_Call { + return &Builder_WithSequentialMode_Call{Call: _e.mock.On("WithSequentialMode")} +} + +func (_c *Builder_WithSequentialMode_Call) Run(run func()) *Builder_WithSequentialMode_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Builder_WithSequentialMode_Call) Return(_a0 config.Builder) *Builder_WithSequentialMode_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithSequentialMode_Call) RunAndReturn(run func() config.Builder) *Builder_WithSequentialMode_Call { + _c.Call.Return(run) + return _c +} + +// WithSubject provides a mock function with given fields: subject, isUTF8 +func (_m *Builder) WithSubject(subject string, isUTF8 bool) config.Builder { + ret := _m.Called(subject, isUTF8) + + if len(ret) == 0 { + panic("no return value specified for WithSubject") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(string, bool) config.Builder); ok { + r0 = rf(subject, isUTF8) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithSubject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithSubject' +type Builder_WithSubject_Call struct { + *mock.Call +} + +// WithSubject is a helper method to define mock.On call +// - subject string +// - isUTF8 bool +func (_e *Builder_Expecter) WithSubject(subject interface{}, isUTF8 interface{}) *Builder_WithSubject_Call { + return &Builder_WithSubject_Call{Call: _e.mock.On("WithSubject", subject, isUTF8)} +} + +func (_c *Builder_WithSubject_Call) Run(run func(subject string, isUTF8 bool)) *Builder_WithSubject_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(bool)) + }) + return _c +} + +func (_c *Builder_WithSubject_Call) Return(_a0 config.Builder) *Builder_WithSubject_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithSubject_Call) RunAndReturn(run func(string, bool) config.Builder) *Builder_WithSubject_Call { + _c.Call.Return(run) + return _c +} + +// WithTitle provides a mock function with given fields: title, isUTF8 +func (_m *Builder) WithTitle(title string, isUTF8 bool) config.Builder { + ret := _m.Called(title, isUTF8) + + if len(ret) == 0 { + panic("no return value specified for WithTitle") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(string, bool) config.Builder); ok { + r0 = rf(title, isUTF8) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithTitle_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithTitle' +type Builder_WithTitle_Call struct { + *mock.Call +} + +// WithTitle is a helper method to define mock.On call +// - title string +// - isUTF8 bool +func (_e *Builder_Expecter) WithTitle(title interface{}, isUTF8 interface{}) *Builder_WithTitle_Call { + return &Builder_WithTitle_Call{Call: _e.mock.On("WithTitle", title, isUTF8)} +} + +func (_c *Builder_WithTitle_Call) Run(run func(title string, isUTF8 bool)) *Builder_WithTitle_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(bool)) + }) + return _c +} + +func (_c *Builder_WithTitle_Call) Return(_a0 config.Builder) *Builder_WithTitle_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Builder_WithTitle_Call) RunAndReturn(run func(string, bool) config.Builder) *Builder_WithTitle_Call { + _c.Call.Return(run) + return _c +} + +// WithTopMargin provides a mock function with given fields: top +func (_m *Builder) WithTopMargin(top float64) config.Builder { + ret := _m.Called(top) + + if len(ret) == 0 { + panic("no return value specified for WithTopMargin") + } + + var r0 config.Builder + if rf, ok := ret.Get(0).(func(float64) config.Builder); ok { + r0 = rf(top) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.Builder) + } + } + + return r0 +} + +// Builder_WithTopMargin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WithTopMargin' +type Builder_WithTopMargin_Call struct { + *mock.Call +} + +// WithTopMargin is a helper method to define mock.On call +// - top float64 +func (_e *Builder_Expecter) WithTopMargin(top interface{}) *Builder_WithTopMargin_Call { + return &Builder_WithTopMargin_Call{Call: _e.mock.On("WithTopMargin", top)} } -func (_c *Builder_Build_Call) Run(run func(cfg *entity.Config, _a1 cache.Cache)) *Builder_Build_Call { +func (_c *Builder_WithTopMargin_Call) Run(run func(top float64)) *Builder_WithTopMargin_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*entity.Config), args[1].(cache.Cache)) + run(args[0].(float64)) }) return _c } -func (_c *Builder_Build_Call) Return(_a0 *gofpdf.Dependencies) *Builder_Build_Call { +func (_c *Builder_WithTopMargin_Call) Return(_a0 config.Builder) *Builder_WithTopMargin_Call { _c.Call.Return(_a0) return _c } -func (_c *Builder_Build_Call) RunAndReturn(run func(*entity.Config, cache.Cache) *gofpdf.Dependencies) *Builder_Build_Call { +func (_c *Builder_WithTopMargin_Call) RunAndReturn(run func(float64) config.Builder) *Builder_WithTopMargin_Call { _c.Call.Return(run) return _c } diff --git a/mocks/BuilderProvider.go b/mocks/BuilderProvider.go new file mode 100644 index 00000000..71b0e59d --- /dev/null +++ b/mocks/BuilderProvider.go @@ -0,0 +1,89 @@ +// Code generated by mockery v2.42.0. DO NOT EDIT. + +package mocks + +import ( + cache "github.com/johnfercher/maroto/v2/internal/cache" + entity "github.com/johnfercher/maroto/v2/pkg/core/entity" + + gofpdf "github.com/johnfercher/maroto/v2/internal/providers/gofpdf" + + mock "github.com/stretchr/testify/mock" +) + +// BuilderProvider is an autogenerated mock type for the BuilderProvider type +type BuilderProvider struct { + mock.Mock +} + +type BuilderProvider_Expecter struct { + mock *mock.Mock +} + +func (_m *BuilderProvider) EXPECT() *BuilderProvider_Expecter { + return &BuilderProvider_Expecter{mock: &_m.Mock} +} + +// Build provides a mock function with given fields: cfg, _a1 +func (_m *BuilderProvider) Build(cfg *entity.Config, _a1 cache.Cache) *gofpdf.Dependencies { + ret := _m.Called(cfg, _a1) + + if len(ret) == 0 { + panic("no return value specified for Build") + } + + var r0 *gofpdf.Dependencies + if rf, ok := ret.Get(0).(func(*entity.Config, cache.Cache) *gofpdf.Dependencies); ok { + r0 = rf(cfg, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*gofpdf.Dependencies) + } + } + + return r0 +} + +// BuilderProvider_Build_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Build' +type BuilderProvider_Build_Call struct { + *mock.Call +} + +// Build is a helper method to define mock.On call +// - cfg *entity.Config +// - _a1 cache.Cache +func (_e *BuilderProvider_Expecter) Build(cfg interface{}, _a1 interface{}) *BuilderProvider_Build_Call { + return &BuilderProvider_Build_Call{Call: _e.mock.On("Build", cfg, _a1)} +} + +func (_c *BuilderProvider_Build_Call) Run(run func(cfg *entity.Config, _a1 cache.Cache)) *BuilderProvider_Build_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*entity.Config), args[1].(cache.Cache)) + }) + return _c +} + +func (_c *BuilderProvider_Build_Call) Return(_a0 *gofpdf.Dependencies) *BuilderProvider_Build_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *BuilderProvider_Build_Call) RunAndReturn(run func(*entity.Config, cache.Cache) *gofpdf.Dependencies) *BuilderProvider_Build_Call { + _c.Call.Return(run) + return _c +} + +// NewBuilderProvider creates a new instance of BuilderProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewBuilderProvider(t interface { + mock.TestingT + Cleanup(func()) +}, +) *BuilderProvider { + mock := &BuilderProvider{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/Componentmapper.go b/mocks/Componentmapper.go new file mode 100644 index 00000000..b6f4c978 --- /dev/null +++ b/mocks/Componentmapper.go @@ -0,0 +1,95 @@ +// Code generated by mockery v2.42.0. DO NOT EDIT. + +package mocks + +import ( + processorprovider "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" + mock "github.com/stretchr/testify/mock" +) + +// Componentmapper is an autogenerated mock type for the Componentmapper type +type Componentmapper struct { + mock.Mock +} + +type Componentmapper_Expecter struct { + mock *mock.Mock +} + +func (_m *Componentmapper) EXPECT() *Componentmapper_Expecter { + return &Componentmapper_Expecter{mock: &_m.Mock} +} + +// Generate provides a mock function with given fields: content, provider +func (_m *Componentmapper) Generate(content map[string]interface{}, provider processorprovider.ProcessorProvider) ([]processorprovider.ProviderComponent, error) { + ret := _m.Called(content, provider) + + if len(ret) == 0 { + panic("no return value specified for Generate") + } + + var r0 []processorprovider.ProviderComponent + var r1 error + if rf, ok := ret.Get(0).(func(map[string]interface{}, processorprovider.ProcessorProvider) ([]processorprovider.ProviderComponent, error)); ok { + return rf(content, provider) + } + if rf, ok := ret.Get(0).(func(map[string]interface{}, processorprovider.ProcessorProvider) []processorprovider.ProviderComponent); ok { + r0 = rf(content, provider) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]processorprovider.ProviderComponent) + } + } + + if rf, ok := ret.Get(1).(func(map[string]interface{}, processorprovider.ProcessorProvider) error); ok { + r1 = rf(content, provider) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Componentmapper_Generate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Generate' +type Componentmapper_Generate_Call struct { + *mock.Call +} + +// Generate is a helper method to define mock.On call +// - content map[string]interface{} +// - provider processorprovider.ProcessorProvider +func (_e *Componentmapper_Expecter) Generate(content interface{}, provider interface{}) *Componentmapper_Generate_Call { + return &Componentmapper_Generate_Call{Call: _e.mock.On("Generate", content, provider)} +} + +func (_c *Componentmapper_Generate_Call) Run(run func(content map[string]interface{}, provider processorprovider.ProcessorProvider)) *Componentmapper_Generate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(map[string]interface{}), args[1].(processorprovider.ProcessorProvider)) + }) + return _c +} + +func (_c *Componentmapper_Generate_Call) Return(_a0 []processorprovider.ProviderComponent, _a1 error) *Componentmapper_Generate_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Componentmapper_Generate_Call) RunAndReturn(run func(map[string]interface{}, processorprovider.ProcessorProvider) ([]processorprovider.ProviderComponent, error)) *Componentmapper_Generate_Call { + _c.Call.Return(run) + return _c +} + +// NewComponentmapper creates a new instance of Componentmapper. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewComponentmapper(t interface { + mock.TestingT + Cleanup(func()) +}, +) *Componentmapper { + mock := &Componentmapper{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/Deserializer.go b/mocks/Deserializer.go new file mode 100644 index 00000000..b5dcd4c4 --- /dev/null +++ b/mocks/Deserializer.go @@ -0,0 +1,91 @@ +// Code generated by mockery v2.42.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// Deserializer is an autogenerated mock type for the Deserializer type +type Deserializer struct { + mock.Mock +} + +type Deserializer_Expecter struct { + mock *mock.Mock +} + +func (_m *Deserializer) EXPECT() *Deserializer_Expecter { + return &Deserializer_Expecter{mock: &_m.Mock} +} + +// Deserialize provides a mock function with given fields: document +func (_m *Deserializer) Deserialize(document string) (map[string]interface{}, error) { + ret := _m.Called(document) + + if len(ret) == 0 { + panic("no return value specified for Deserialize") + } + + var r0 map[string]interface{} + var r1 error + if rf, ok := ret.Get(0).(func(string) (map[string]interface{}, error)); ok { + return rf(document) + } + if rf, ok := ret.Get(0).(func(string) map[string]interface{}); ok { + r0 = rf(document) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]interface{}) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(document) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Deserializer_Deserialize_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Deserialize' +type Deserializer_Deserialize_Call struct { + *mock.Call +} + +// Deserialize is a helper method to define mock.On call +// - document string +func (_e *Deserializer_Expecter) Deserialize(document interface{}) *Deserializer_Deserialize_Call { + return &Deserializer_Deserialize_Call{Call: _e.mock.On("Deserialize", document)} +} + +func (_c *Deserializer_Deserialize_Call) Run(run func(document string)) *Deserializer_Deserialize_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *Deserializer_Deserialize_Call) Return(_a0 map[string]interface{}, _a1 error) *Deserializer_Deserialize_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Deserializer_Deserialize_Call) RunAndReturn(run func(string) (map[string]interface{}, error)) *Deserializer_Deserialize_Call { + _c.Call.Return(run) + return _c +} + +// NewDeserializer creates a new instance of Deserializer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewDeserializer(t interface { + mock.TestingT + Cleanup(func()) +}, +) *Deserializer { + mock := &Deserializer{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/GenerateComponent.go b/mocks/GenerateComponent.go new file mode 100644 index 00000000..12e1334d --- /dev/null +++ b/mocks/GenerateComponent.go @@ -0,0 +1,95 @@ +// Code generated by mockery v2.42.0. DO NOT EDIT. + +package mocks + +import ( + mappers "github.com/johnfercher/maroto/v2/pkg/processor/mappers" + mock "github.com/stretchr/testify/mock" +) + +// GenerateComponent is an autogenerated mock type for the GenerateComponent type +type GenerateComponent struct { + mock.Mock +} + +type GenerateComponent_Expecter struct { + mock *mock.Mock +} + +func (_m *GenerateComponent) EXPECT() *GenerateComponent_Expecter { + return &GenerateComponent_Expecter{mock: &_m.Mock} +} + +// Execute provides a mock function with given fields: document, sourceKey +func (_m *GenerateComponent) Execute(document interface{}, sourceKey string) (mappers.OrderedComponents, error) { + ret := _m.Called(document, sourceKey) + + if len(ret) == 0 { + panic("no return value specified for Execute") + } + + var r0 mappers.OrderedComponents + var r1 error + if rf, ok := ret.Get(0).(func(interface{}, string) (mappers.OrderedComponents, error)); ok { + return rf(document, sourceKey) + } + if rf, ok := ret.Get(0).(func(interface{}, string) mappers.OrderedComponents); ok { + r0 = rf(document, sourceKey) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(mappers.OrderedComponents) + } + } + + if rf, ok := ret.Get(1).(func(interface{}, string) error); ok { + r1 = rf(document, sourceKey) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GenerateComponent_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' +type GenerateComponent_Execute_Call struct { + *mock.Call +} + +// Execute is a helper method to define mock.On call +// - document interface{} +// - sourceKey string +func (_e *GenerateComponent_Expecter) Execute(document interface{}, sourceKey interface{}) *GenerateComponent_Execute_Call { + return &GenerateComponent_Execute_Call{Call: _e.mock.On("Execute", document, sourceKey)} +} + +func (_c *GenerateComponent_Execute_Call) Run(run func(document interface{}, sourceKey string)) *GenerateComponent_Execute_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(interface{}), args[1].(string)) + }) + return _c +} + +func (_c *GenerateComponent_Execute_Call) Return(_a0 mappers.OrderedComponents, _a1 error) *GenerateComponent_Execute_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *GenerateComponent_Execute_Call) RunAndReturn(run func(interface{}, string) (mappers.OrderedComponents, error)) *GenerateComponent_Execute_Call { + _c.Call.Return(run) + return _c +} + +// NewGenerateComponent creates a new instance of GenerateComponent. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewGenerateComponent(t interface { + mock.TestingT + Cleanup(func()) +}, +) *GenerateComponent { + mock := &GenerateComponent{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/Loader.go b/mocks/Loader.go new file mode 100644 index 00000000..ffe16105 --- /dev/null +++ b/mocks/Loader.go @@ -0,0 +1,137 @@ +// Code generated by mockery v2.42.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// Loader is an autogenerated mock type for the Loader type +type Loader struct { + mock.Mock +} + +type Loader_Expecter struct { + mock *mock.Mock +} + +func (_m *Loader) EXPECT() *Loader_Expecter { + return &Loader_Expecter{mock: &_m.Mock} +} + +// GetExt provides a mock function with given fields: path +func (_m *Loader) GetExt(path string) string { + ret := _m.Called(path) + + if len(ret) == 0 { + panic("no return value specified for GetExt") + } + + var r0 string + if rf, ok := ret.Get(0).(func(string) string); ok { + r0 = rf(path) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Loader_GetExt_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExt' +type Loader_GetExt_Call struct { + *mock.Call +} + +// GetExt is a helper method to define mock.On call +// - path string +func (_e *Loader_Expecter) GetExt(path interface{}) *Loader_GetExt_Call { + return &Loader_GetExt_Call{Call: _e.mock.On("GetExt", path)} +} + +func (_c *Loader_GetExt_Call) Run(run func(path string)) *Loader_GetExt_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *Loader_GetExt_Call) Return(_a0 string) *Loader_GetExt_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Loader_GetExt_Call) RunAndReturn(run func(string) string) *Loader_GetExt_Call { + _c.Call.Return(run) + return _c +} + +// Load provides a mock function with given fields: path +func (_m *Loader) Load(path string) ([]byte, error) { + ret := _m.Called(path) + + if len(ret) == 0 { + panic("no return value specified for Load") + } + + var r0 []byte + var r1 error + if rf, ok := ret.Get(0).(func(string) ([]byte, error)); ok { + return rf(path) + } + if rf, ok := ret.Get(0).(func(string) []byte); ok { + r0 = rf(path) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(path) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Loader_Load_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Load' +type Loader_Load_Call struct { + *mock.Call +} + +// Load is a helper method to define mock.On call +// - path string +func (_e *Loader_Expecter) Load(path interface{}) *Loader_Load_Call { + return &Loader_Load_Call{Call: _e.mock.On("Load", path)} +} + +func (_c *Loader_Load_Call) Run(run func(path string)) *Loader_Load_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *Loader_Load_Call) Return(_a0 []byte, _a1 error) *Loader_Load_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *Loader_Load_Call) RunAndReturn(run func(string) ([]byte, error)) *Loader_Load_Call { + _c.Call.Return(run) + return _c +} + +// NewLoader creates a new instance of Loader. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewLoader(t interface { + mock.TestingT + Cleanup(func()) +}, +) *Loader { + mock := &Loader{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/OrderedComponents.go b/mocks/OrderedComponents.go new file mode 100644 index 00000000..577c94c2 --- /dev/null +++ b/mocks/OrderedComponents.go @@ -0,0 +1,140 @@ +// Code generated by mockery v2.42.0. DO NOT EDIT. + +package mocks + +import ( + processorprovider "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" + mock "github.com/stretchr/testify/mock" +) + +// OrderedComponents is an autogenerated mock type for the OrderedComponents type +type OrderedComponents struct { + mock.Mock +} + +type OrderedComponents_Expecter struct { + mock *mock.Mock +} + +func (_m *OrderedComponents) EXPECT() *OrderedComponents_Expecter { + return &OrderedComponents_Expecter{mock: &_m.Mock} +} + +// Generate provides a mock function with given fields: content, provider +func (_m *OrderedComponents) Generate(content map[string]interface{}, provider processorprovider.ProcessorProvider) ([]processorprovider.ProviderComponent, error) { + ret := _m.Called(content, provider) + + if len(ret) == 0 { + panic("no return value specified for Generate") + } + + var r0 []processorprovider.ProviderComponent + var r1 error + if rf, ok := ret.Get(0).(func(map[string]interface{}, processorprovider.ProcessorProvider) ([]processorprovider.ProviderComponent, error)); ok { + return rf(content, provider) + } + if rf, ok := ret.Get(0).(func(map[string]interface{}, processorprovider.ProcessorProvider) []processorprovider.ProviderComponent); ok { + r0 = rf(content, provider) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]processorprovider.ProviderComponent) + } + } + + if rf, ok := ret.Get(1).(func(map[string]interface{}, processorprovider.ProcessorProvider) error); ok { + r1 = rf(content, provider) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// OrderedComponents_Generate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Generate' +type OrderedComponents_Generate_Call struct { + *mock.Call +} + +// Generate is a helper method to define mock.On call +// - content map[string]interface{} +// - provider processorprovider.ProcessorProvider +func (_e *OrderedComponents_Expecter) Generate(content interface{}, provider interface{}) *OrderedComponents_Generate_Call { + return &OrderedComponents_Generate_Call{Call: _e.mock.On("Generate", content, provider)} +} + +func (_c *OrderedComponents_Generate_Call) Run(run func(content map[string]interface{}, provider processorprovider.ProcessorProvider)) *OrderedComponents_Generate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(map[string]interface{}), args[1].(processorprovider.ProcessorProvider)) + }) + return _c +} + +func (_c *OrderedComponents_Generate_Call) Return(_a0 []processorprovider.ProviderComponent, _a1 error) *OrderedComponents_Generate_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *OrderedComponents_Generate_Call) RunAndReturn(run func(map[string]interface{}, processorprovider.ProcessorProvider) ([]processorprovider.ProviderComponent, error)) *OrderedComponents_Generate_Call { + _c.Call.Return(run) + return _c +} + +// GetOrder provides a mock function with given fields: +func (_m *OrderedComponents) GetOrder() int { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetOrder") + } + + var r0 int + if rf, ok := ret.Get(0).(func() int); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int) + } + + return r0 +} + +// OrderedComponents_GetOrder_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetOrder' +type OrderedComponents_GetOrder_Call struct { + *mock.Call +} + +// GetOrder is a helper method to define mock.On call +func (_e *OrderedComponents_Expecter) GetOrder() *OrderedComponents_GetOrder_Call { + return &OrderedComponents_GetOrder_Call{Call: _e.mock.On("GetOrder")} +} + +func (_c *OrderedComponents_GetOrder_Call) Run(run func()) *OrderedComponents_GetOrder_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *OrderedComponents_GetOrder_Call) Return(_a0 int) *OrderedComponents_GetOrder_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *OrderedComponents_GetOrder_Call) RunAndReturn(run func() int) *OrderedComponents_GetOrder_Call { + _c.Call.Return(run) + return _c +} + +// NewOrderedComponents creates a new instance of OrderedComponents. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewOrderedComponents(t interface { + mock.TestingT + Cleanup(func()) +}, +) *OrderedComponents { + mock := &OrderedComponents{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/Processor.go b/mocks/Processor.go new file mode 100644 index 00000000..c8d28d27 --- /dev/null +++ b/mocks/Processor.go @@ -0,0 +1,129 @@ +// Code generated by mockery v2.42.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// Processor is an autogenerated mock type for the Processor type +type Processor struct { + mock.Mock +} + +type Processor_Expecter struct { + mock *mock.Mock +} + +func (_m *Processor) EXPECT() *Processor_Expecter { + return &Processor_Expecter{mock: &_m.Mock} +} + +// GenerateDocument provides a mock function with given fields: templateName, content +func (_m *Processor) GenerateDocument(templateName string, content string) []byte { + ret := _m.Called(templateName, content) + + if len(ret) == 0 { + panic("no return value specified for GenerateDocument") + } + + var r0 []byte + if rf, ok := ret.Get(0).(func(string, string) []byte); ok { + r0 = rf(templateName, content) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } + } + + return r0 +} + +// Processor_GenerateDocument_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GenerateDocument' +type Processor_GenerateDocument_Call struct { + *mock.Call +} + +// GenerateDocument is a helper method to define mock.On call +// - templateName string +// - content string +func (_e *Processor_Expecter) GenerateDocument(templateName interface{}, content interface{}) *Processor_GenerateDocument_Call { + return &Processor_GenerateDocument_Call{Call: _e.mock.On("GenerateDocument", templateName, content)} +} + +func (_c *Processor_GenerateDocument_Call) Run(run func(templateName string, content string)) *Processor_GenerateDocument_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *Processor_GenerateDocument_Call) Return(_a0 []byte) *Processor_GenerateDocument_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Processor_GenerateDocument_Call) RunAndReturn(run func(string, string) []byte) *Processor_GenerateDocument_Call { + _c.Call.Return(run) + return _c +} + +// RegisterTemplate provides a mock function with given fields: templateName, template +func (_m *Processor) RegisterTemplate(templateName string, template string) error { + ret := _m.Called(templateName, template) + + if len(ret) == 0 { + panic("no return value specified for RegisterTemplate") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string, string) error); ok { + r0 = rf(templateName, template) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Processor_RegisterTemplate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RegisterTemplate' +type Processor_RegisterTemplate_Call struct { + *mock.Call +} + +// RegisterTemplate is a helper method to define mock.On call +// - templateName string +// - template string +func (_e *Processor_Expecter) RegisterTemplate(templateName interface{}, template interface{}) *Processor_RegisterTemplate_Call { + return &Processor_RegisterTemplate_Call{Call: _e.mock.On("RegisterTemplate", templateName, template)} +} + +func (_c *Processor_RegisterTemplate_Call) Run(run func(templateName string, template string)) *Processor_RegisterTemplate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *Processor_RegisterTemplate_Call) Return(_a0 error) *Processor_RegisterTemplate_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Processor_RegisterTemplate_Call) RunAndReturn(run func(string, string) error) *Processor_RegisterTemplate_Call { + _c.Call.Return(run) + return _c +} + +// NewProcessor creates a new instance of Processor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewProcessor(t interface { + mock.TestingT + Cleanup(func()) +}, +) *Processor { + mock := &Processor{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/ProcessorProvider.go b/mocks/ProcessorProvider.go new file mode 100644 index 00000000..5d881003 --- /dev/null +++ b/mocks/ProcessorProvider.go @@ -0,0 +1,1027 @@ +// Code generated by mockery v2.42.0. DO NOT EDIT. + +package mocks + +import ( + core "github.com/johnfercher/maroto/v2/pkg/core" + mock "github.com/stretchr/testify/mock" + + node "github.com/johnfercher/go-tree/node" + + processorprovider "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" + + propsmapper "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" +) + +// ProcessorProvider is an autogenerated mock type for the ProcessorProvider type +type ProcessorProvider struct { + mock.Mock +} + +type ProcessorProvider_Expecter struct { + mock *mock.Mock +} + +func (_m *ProcessorProvider) EXPECT() *ProcessorProvider_Expecter { + return &ProcessorProvider_Expecter{mock: &_m.Mock} +} + +// AddFooter provides a mock function with given fields: footer +func (_m *ProcessorProvider) AddFooter(footer ...processorprovider.ProviderComponent) (processorprovider.ProcessorProvider, error) { + _va := make([]interface{}, len(footer)) + for _i := range footer { + _va[_i] = footer[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for AddFooter") + } + + var r0 processorprovider.ProcessorProvider + var r1 error + if rf, ok := ret.Get(0).(func(...processorprovider.ProviderComponent) (processorprovider.ProcessorProvider, error)); ok { + return rf(footer...) + } + if rf, ok := ret.Get(0).(func(...processorprovider.ProviderComponent) processorprovider.ProcessorProvider); ok { + r0 = rf(footer...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(processorprovider.ProcessorProvider) + } + } + + if rf, ok := ret.Get(1).(func(...processorprovider.ProviderComponent) error); ok { + r1 = rf(footer...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProcessorProvider_AddFooter_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddFooter' +type ProcessorProvider_AddFooter_Call struct { + *mock.Call +} + +// AddFooter is a helper method to define mock.On call +// - footer ...processorprovider.ProviderComponent +func (_e *ProcessorProvider_Expecter) AddFooter(footer ...interface{}) *ProcessorProvider_AddFooter_Call { + return &ProcessorProvider_AddFooter_Call{Call: _e.mock.On("AddFooter", + append([]interface{}{}, footer...)...)} +} + +func (_c *ProcessorProvider_AddFooter_Call) Run(run func(footer ...processorprovider.ProviderComponent)) *ProcessorProvider_AddFooter_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]processorprovider.ProviderComponent, len(args)-0) + for i, a := range args[0:] { + if a != nil { + variadicArgs[i] = a.(processorprovider.ProviderComponent) + } + } + run(variadicArgs...) + }) + return _c +} + +func (_c *ProcessorProvider_AddFooter_Call) Return(_a0 processorprovider.ProcessorProvider, _a1 error) *ProcessorProvider_AddFooter_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProcessorProvider_AddFooter_Call) RunAndReturn(run func(...processorprovider.ProviderComponent) (processorprovider.ProcessorProvider, error)) *ProcessorProvider_AddFooter_Call { + _c.Call.Return(run) + return _c +} + +// AddHeader provides a mock function with given fields: header +func (_m *ProcessorProvider) AddHeader(header ...processorprovider.ProviderComponent) (processorprovider.ProcessorProvider, error) { + _va := make([]interface{}, len(header)) + for _i := range header { + _va[_i] = header[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for AddHeader") + } + + var r0 processorprovider.ProcessorProvider + var r1 error + if rf, ok := ret.Get(0).(func(...processorprovider.ProviderComponent) (processorprovider.ProcessorProvider, error)); ok { + return rf(header...) + } + if rf, ok := ret.Get(0).(func(...processorprovider.ProviderComponent) processorprovider.ProcessorProvider); ok { + r0 = rf(header...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(processorprovider.ProcessorProvider) + } + } + + if rf, ok := ret.Get(1).(func(...processorprovider.ProviderComponent) error); ok { + r1 = rf(header...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProcessorProvider_AddHeader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddHeader' +type ProcessorProvider_AddHeader_Call struct { + *mock.Call +} + +// AddHeader is a helper method to define mock.On call +// - header ...processorprovider.ProviderComponent +func (_e *ProcessorProvider_Expecter) AddHeader(header ...interface{}) *ProcessorProvider_AddHeader_Call { + return &ProcessorProvider_AddHeader_Call{Call: _e.mock.On("AddHeader", + append([]interface{}{}, header...)...)} +} + +func (_c *ProcessorProvider_AddHeader_Call) Run(run func(header ...processorprovider.ProviderComponent)) *ProcessorProvider_AddHeader_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]processorprovider.ProviderComponent, len(args)-0) + for i, a := range args[0:] { + if a != nil { + variadicArgs[i] = a.(processorprovider.ProviderComponent) + } + } + run(variadicArgs...) + }) + return _c +} + +func (_c *ProcessorProvider_AddHeader_Call) Return(_a0 processorprovider.ProcessorProvider, _a1 error) *ProcessorProvider_AddHeader_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProcessorProvider_AddHeader_Call) RunAndReturn(run func(...processorprovider.ProviderComponent) (processorprovider.ProcessorProvider, error)) *ProcessorProvider_AddHeader_Call { + _c.Call.Return(run) + return _c +} + +// AddPages provides a mock function with given fields: pages +func (_m *ProcessorProvider) AddPages(pages ...processorprovider.ProviderComponent) (processorprovider.ProcessorProvider, error) { + _va := make([]interface{}, len(pages)) + for _i := range pages { + _va[_i] = pages[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for AddPages") + } + + var r0 processorprovider.ProcessorProvider + var r1 error + if rf, ok := ret.Get(0).(func(...processorprovider.ProviderComponent) (processorprovider.ProcessorProvider, error)); ok { + return rf(pages...) + } + if rf, ok := ret.Get(0).(func(...processorprovider.ProviderComponent) processorprovider.ProcessorProvider); ok { + r0 = rf(pages...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(processorprovider.ProcessorProvider) + } + } + + if rf, ok := ret.Get(1).(func(...processorprovider.ProviderComponent) error); ok { + r1 = rf(pages...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProcessorProvider_AddPages_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddPages' +type ProcessorProvider_AddPages_Call struct { + *mock.Call +} + +// AddPages is a helper method to define mock.On call +// - pages ...processorprovider.ProviderComponent +func (_e *ProcessorProvider_Expecter) AddPages(pages ...interface{}) *ProcessorProvider_AddPages_Call { + return &ProcessorProvider_AddPages_Call{Call: _e.mock.On("AddPages", + append([]interface{}{}, pages...)...)} +} + +func (_c *ProcessorProvider_AddPages_Call) Run(run func(pages ...processorprovider.ProviderComponent)) *ProcessorProvider_AddPages_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]processorprovider.ProviderComponent, len(args)-0) + for i, a := range args[0:] { + if a != nil { + variadicArgs[i] = a.(processorprovider.ProviderComponent) + } + } + run(variadicArgs...) + }) + return _c +} + +func (_c *ProcessorProvider_AddPages_Call) Return(_a0 processorprovider.ProcessorProvider, _a1 error) *ProcessorProvider_AddPages_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProcessorProvider_AddPages_Call) RunAndReturn(run func(...processorprovider.ProviderComponent) (processorprovider.ProcessorProvider, error)) *ProcessorProvider_AddPages_Call { + _c.Call.Return(run) + return _c +} + +// CreateBarCode provides a mock function with given fields: value, props +func (_m *ProcessorProvider) CreateBarCode(value string, props ...*propsmapper.Barcode) processorprovider.ProviderComponent { + _va := make([]interface{}, len(props)) + for _i := range props { + _va[_i] = props[_i] + } + var _ca []interface{} + _ca = append(_ca, value) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CreateBarCode") + } + + var r0 processorprovider.ProviderComponent + if rf, ok := ret.Get(0).(func(string, ...*propsmapper.Barcode) processorprovider.ProviderComponent); ok { + r0 = rf(value, props...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(processorprovider.ProviderComponent) + } + } + + return r0 +} + +// ProcessorProvider_CreateBarCode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateBarCode' +type ProcessorProvider_CreateBarCode_Call struct { + *mock.Call +} + +// CreateBarCode is a helper method to define mock.On call +// - value string +// - props ...*propsmapper.Barcode +func (_e *ProcessorProvider_Expecter) CreateBarCode(value interface{}, props ...interface{}) *ProcessorProvider_CreateBarCode_Call { + return &ProcessorProvider_CreateBarCode_Call{Call: _e.mock.On("CreateBarCode", + append([]interface{}{value}, props...)...)} +} + +func (_c *ProcessorProvider_CreateBarCode_Call) Run(run func(value string, props ...*propsmapper.Barcode)) *ProcessorProvider_CreateBarCode_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]*propsmapper.Barcode, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(*propsmapper.Barcode) + } + } + run(args[0].(string), variadicArgs...) + }) + return _c +} + +func (_c *ProcessorProvider_CreateBarCode_Call) Return(_a0 processorprovider.ProviderComponent) *ProcessorProvider_CreateBarCode_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProcessorProvider_CreateBarCode_Call) RunAndReturn(run func(string, ...*propsmapper.Barcode) processorprovider.ProviderComponent) *ProcessorProvider_CreateBarCode_Call { + _c.Call.Return(run) + return _c +} + +// CreateCol provides a mock function with given fields: size, props, components +func (_m *ProcessorProvider) CreateCol(size int, props *propsmapper.Cell, components ...processorprovider.ProviderComponent) (processorprovider.ProviderComponent, error) { + _va := make([]interface{}, len(components)) + for _i := range components { + _va[_i] = components[_i] + } + var _ca []interface{} + _ca = append(_ca, size, props) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CreateCol") + } + + var r0 processorprovider.ProviderComponent + var r1 error + if rf, ok := ret.Get(0).(func(int, *propsmapper.Cell, ...processorprovider.ProviderComponent) (processorprovider.ProviderComponent, error)); ok { + return rf(size, props, components...) + } + if rf, ok := ret.Get(0).(func(int, *propsmapper.Cell, ...processorprovider.ProviderComponent) processorprovider.ProviderComponent); ok { + r0 = rf(size, props, components...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(processorprovider.ProviderComponent) + } + } + + if rf, ok := ret.Get(1).(func(int, *propsmapper.Cell, ...processorprovider.ProviderComponent) error); ok { + r1 = rf(size, props, components...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProcessorProvider_CreateCol_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateCol' +type ProcessorProvider_CreateCol_Call struct { + *mock.Call +} + +// CreateCol is a helper method to define mock.On call +// - size int +// - props *propsmapper.Cell +// - components ...processorprovider.ProviderComponent +func (_e *ProcessorProvider_Expecter) CreateCol(size interface{}, props interface{}, components ...interface{}) *ProcessorProvider_CreateCol_Call { + return &ProcessorProvider_CreateCol_Call{Call: _e.mock.On("CreateCol", + append([]interface{}{size, props}, components...)...)} +} + +func (_c *ProcessorProvider_CreateCol_Call) Run(run func(size int, props *propsmapper.Cell, components ...processorprovider.ProviderComponent)) *ProcessorProvider_CreateCol_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]processorprovider.ProviderComponent, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(processorprovider.ProviderComponent) + } + } + run(args[0].(int), args[1].(*propsmapper.Cell), variadicArgs...) + }) + return _c +} + +func (_c *ProcessorProvider_CreateCol_Call) Return(_a0 processorprovider.ProviderComponent, _a1 error) *ProcessorProvider_CreateCol_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProcessorProvider_CreateCol_Call) RunAndReturn(run func(int, *propsmapper.Cell, ...processorprovider.ProviderComponent) (processorprovider.ProviderComponent, error)) *ProcessorProvider_CreateCol_Call { + _c.Call.Return(run) + return _c +} + +// CreateImage provides a mock function with given fields: path, props +func (_m *ProcessorProvider) CreateImage(path string, props ...*propsmapper.Rect) (processorprovider.ProviderComponent, error) { + _va := make([]interface{}, len(props)) + for _i := range props { + _va[_i] = props[_i] + } + var _ca []interface{} + _ca = append(_ca, path) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CreateImage") + } + + var r0 processorprovider.ProviderComponent + var r1 error + if rf, ok := ret.Get(0).(func(string, ...*propsmapper.Rect) (processorprovider.ProviderComponent, error)); ok { + return rf(path, props...) + } + if rf, ok := ret.Get(0).(func(string, ...*propsmapper.Rect) processorprovider.ProviderComponent); ok { + r0 = rf(path, props...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(processorprovider.ProviderComponent) + } + } + + if rf, ok := ret.Get(1).(func(string, ...*propsmapper.Rect) error); ok { + r1 = rf(path, props...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProcessorProvider_CreateImage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateImage' +type ProcessorProvider_CreateImage_Call struct { + *mock.Call +} + +// CreateImage is a helper method to define mock.On call +// - path string +// - props ...*propsmapper.Rect +func (_e *ProcessorProvider_Expecter) CreateImage(path interface{}, props ...interface{}) *ProcessorProvider_CreateImage_Call { + return &ProcessorProvider_CreateImage_Call{Call: _e.mock.On("CreateImage", + append([]interface{}{path}, props...)...)} +} + +func (_c *ProcessorProvider_CreateImage_Call) Run(run func(path string, props ...*propsmapper.Rect)) *ProcessorProvider_CreateImage_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]*propsmapper.Rect, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(*propsmapper.Rect) + } + } + run(args[0].(string), variadicArgs...) + }) + return _c +} + +func (_c *ProcessorProvider_CreateImage_Call) Return(_a0 processorprovider.ProviderComponent, _a1 error) *ProcessorProvider_CreateImage_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProcessorProvider_CreateImage_Call) RunAndReturn(run func(string, ...*propsmapper.Rect) (processorprovider.ProviderComponent, error)) *ProcessorProvider_CreateImage_Call { + _c.Call.Return(run) + return _c +} + +// CreateLine provides a mock function with given fields: props +func (_m *ProcessorProvider) CreateLine(props ...*propsmapper.Line) processorprovider.ProviderComponent { + _va := make([]interface{}, len(props)) + for _i := range props { + _va[_i] = props[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CreateLine") + } + + var r0 processorprovider.ProviderComponent + if rf, ok := ret.Get(0).(func(...*propsmapper.Line) processorprovider.ProviderComponent); ok { + r0 = rf(props...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(processorprovider.ProviderComponent) + } + } + + return r0 +} + +// ProcessorProvider_CreateLine_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateLine' +type ProcessorProvider_CreateLine_Call struct { + *mock.Call +} + +// CreateLine is a helper method to define mock.On call +// - props ...*propsmapper.Line +func (_e *ProcessorProvider_Expecter) CreateLine(props ...interface{}) *ProcessorProvider_CreateLine_Call { + return &ProcessorProvider_CreateLine_Call{Call: _e.mock.On("CreateLine", + append([]interface{}{}, props...)...)} +} + +func (_c *ProcessorProvider_CreateLine_Call) Run(run func(props ...*propsmapper.Line)) *ProcessorProvider_CreateLine_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]*propsmapper.Line, len(args)-0) + for i, a := range args[0:] { + if a != nil { + variadicArgs[i] = a.(*propsmapper.Line) + } + } + run(variadicArgs...) + }) + return _c +} + +func (_c *ProcessorProvider_CreateLine_Call) Return(_a0 processorprovider.ProviderComponent) *ProcessorProvider_CreateLine_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProcessorProvider_CreateLine_Call) RunAndReturn(run func(...*propsmapper.Line) processorprovider.ProviderComponent) *ProcessorProvider_CreateLine_Call { + _c.Call.Return(run) + return _c +} + +// CreateMatrixCode provides a mock function with given fields: value, props +func (_m *ProcessorProvider) CreateMatrixCode(value string, props ...*propsmapper.Rect) processorprovider.ProviderComponent { + _va := make([]interface{}, len(props)) + for _i := range props { + _va[_i] = props[_i] + } + var _ca []interface{} + _ca = append(_ca, value) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CreateMatrixCode") + } + + var r0 processorprovider.ProviderComponent + if rf, ok := ret.Get(0).(func(string, ...*propsmapper.Rect) processorprovider.ProviderComponent); ok { + r0 = rf(value, props...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(processorprovider.ProviderComponent) + } + } + + return r0 +} + +// ProcessorProvider_CreateMatrixCode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateMatrixCode' +type ProcessorProvider_CreateMatrixCode_Call struct { + *mock.Call +} + +// CreateMatrixCode is a helper method to define mock.On call +// - value string +// - props ...*propsmapper.Rect +func (_e *ProcessorProvider_Expecter) CreateMatrixCode(value interface{}, props ...interface{}) *ProcessorProvider_CreateMatrixCode_Call { + return &ProcessorProvider_CreateMatrixCode_Call{Call: _e.mock.On("CreateMatrixCode", + append([]interface{}{value}, props...)...)} +} + +func (_c *ProcessorProvider_CreateMatrixCode_Call) Run(run func(value string, props ...*propsmapper.Rect)) *ProcessorProvider_CreateMatrixCode_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]*propsmapper.Rect, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(*propsmapper.Rect) + } + } + run(args[0].(string), variadicArgs...) + }) + return _c +} + +func (_c *ProcessorProvider_CreateMatrixCode_Call) Return(_a0 processorprovider.ProviderComponent) *ProcessorProvider_CreateMatrixCode_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProcessorProvider_CreateMatrixCode_Call) RunAndReturn(run func(string, ...*propsmapper.Rect) processorprovider.ProviderComponent) *ProcessorProvider_CreateMatrixCode_Call { + _c.Call.Return(run) + return _c +} + +// CreatePage provides a mock function with given fields: components +func (_m *ProcessorProvider) CreatePage(components ...processorprovider.ProviderComponent) (processorprovider.ProviderComponent, error) { + _va := make([]interface{}, len(components)) + for _i := range components { + _va[_i] = components[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CreatePage") + } + + var r0 processorprovider.ProviderComponent + var r1 error + if rf, ok := ret.Get(0).(func(...processorprovider.ProviderComponent) (processorprovider.ProviderComponent, error)); ok { + return rf(components...) + } + if rf, ok := ret.Get(0).(func(...processorprovider.ProviderComponent) processorprovider.ProviderComponent); ok { + r0 = rf(components...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(processorprovider.ProviderComponent) + } + } + + if rf, ok := ret.Get(1).(func(...processorprovider.ProviderComponent) error); ok { + r1 = rf(components...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProcessorProvider_CreatePage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreatePage' +type ProcessorProvider_CreatePage_Call struct { + *mock.Call +} + +// CreatePage is a helper method to define mock.On call +// - components ...processorprovider.ProviderComponent +func (_e *ProcessorProvider_Expecter) CreatePage(components ...interface{}) *ProcessorProvider_CreatePage_Call { + return &ProcessorProvider_CreatePage_Call{Call: _e.mock.On("CreatePage", + append([]interface{}{}, components...)...)} +} + +func (_c *ProcessorProvider_CreatePage_Call) Run(run func(components ...processorprovider.ProviderComponent)) *ProcessorProvider_CreatePage_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]processorprovider.ProviderComponent, len(args)-0) + for i, a := range args[0:] { + if a != nil { + variadicArgs[i] = a.(processorprovider.ProviderComponent) + } + } + run(variadicArgs...) + }) + return _c +} + +func (_c *ProcessorProvider_CreatePage_Call) Return(_a0 processorprovider.ProviderComponent, _a1 error) *ProcessorProvider_CreatePage_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProcessorProvider_CreatePage_Call) RunAndReturn(run func(...processorprovider.ProviderComponent) (processorprovider.ProviderComponent, error)) *ProcessorProvider_CreatePage_Call { + _c.Call.Return(run) + return _c +} + +// CreateQrCode provides a mock function with given fields: value, props +func (_m *ProcessorProvider) CreateQrCode(value string, props ...*propsmapper.Rect) processorprovider.ProviderComponent { + _va := make([]interface{}, len(props)) + for _i := range props { + _va[_i] = props[_i] + } + var _ca []interface{} + _ca = append(_ca, value) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CreateQrCode") + } + + var r0 processorprovider.ProviderComponent + if rf, ok := ret.Get(0).(func(string, ...*propsmapper.Rect) processorprovider.ProviderComponent); ok { + r0 = rf(value, props...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(processorprovider.ProviderComponent) + } + } + + return r0 +} + +// ProcessorProvider_CreateQrCode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateQrCode' +type ProcessorProvider_CreateQrCode_Call struct { + *mock.Call +} + +// CreateQrCode is a helper method to define mock.On call +// - value string +// - props ...*propsmapper.Rect +func (_e *ProcessorProvider_Expecter) CreateQrCode(value interface{}, props ...interface{}) *ProcessorProvider_CreateQrCode_Call { + return &ProcessorProvider_CreateQrCode_Call{Call: _e.mock.On("CreateQrCode", + append([]interface{}{value}, props...)...)} +} + +func (_c *ProcessorProvider_CreateQrCode_Call) Run(run func(value string, props ...*propsmapper.Rect)) *ProcessorProvider_CreateQrCode_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]*propsmapper.Rect, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(*propsmapper.Rect) + } + } + run(args[0].(string), variadicArgs...) + }) + return _c +} + +func (_c *ProcessorProvider_CreateQrCode_Call) Return(_a0 processorprovider.ProviderComponent) *ProcessorProvider_CreateQrCode_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProcessorProvider_CreateQrCode_Call) RunAndReturn(run func(string, ...*propsmapper.Rect) processorprovider.ProviderComponent) *ProcessorProvider_CreateQrCode_Call { + _c.Call.Return(run) + return _c +} + +// CreateRow provides a mock function with given fields: height, props, components +func (_m *ProcessorProvider) CreateRow(height float64, props *propsmapper.Cell, components ...processorprovider.ProviderComponent) (processorprovider.ProviderComponent, error) { + _va := make([]interface{}, len(components)) + for _i := range components { + _va[_i] = components[_i] + } + var _ca []interface{} + _ca = append(_ca, height, props) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CreateRow") + } + + var r0 processorprovider.ProviderComponent + var r1 error + if rf, ok := ret.Get(0).(func(float64, *propsmapper.Cell, ...processorprovider.ProviderComponent) (processorprovider.ProviderComponent, error)); ok { + return rf(height, props, components...) + } + if rf, ok := ret.Get(0).(func(float64, *propsmapper.Cell, ...processorprovider.ProviderComponent) processorprovider.ProviderComponent); ok { + r0 = rf(height, props, components...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(processorprovider.ProviderComponent) + } + } + + if rf, ok := ret.Get(1).(func(float64, *propsmapper.Cell, ...processorprovider.ProviderComponent) error); ok { + r1 = rf(height, props, components...) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProcessorProvider_CreateRow_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateRow' +type ProcessorProvider_CreateRow_Call struct { + *mock.Call +} + +// CreateRow is a helper method to define mock.On call +// - height float64 +// - props *propsmapper.Cell +// - components ...processorprovider.ProviderComponent +func (_e *ProcessorProvider_Expecter) CreateRow(height interface{}, props interface{}, components ...interface{}) *ProcessorProvider_CreateRow_Call { + return &ProcessorProvider_CreateRow_Call{Call: _e.mock.On("CreateRow", + append([]interface{}{height, props}, components...)...)} +} + +func (_c *ProcessorProvider_CreateRow_Call) Run(run func(height float64, props *propsmapper.Cell, components ...processorprovider.ProviderComponent)) *ProcessorProvider_CreateRow_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]processorprovider.ProviderComponent, len(args)-2) + for i, a := range args[2:] { + if a != nil { + variadicArgs[i] = a.(processorprovider.ProviderComponent) + } + } + run(args[0].(float64), args[1].(*propsmapper.Cell), variadicArgs...) + }) + return _c +} + +func (_c *ProcessorProvider_CreateRow_Call) Return(_a0 processorprovider.ProviderComponent, _a1 error) *ProcessorProvider_CreateRow_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProcessorProvider_CreateRow_Call) RunAndReturn(run func(float64, *propsmapper.Cell, ...processorprovider.ProviderComponent) (processorprovider.ProviderComponent, error)) *ProcessorProvider_CreateRow_Call { + _c.Call.Return(run) + return _c +} + +// CreateSignature provides a mock function with given fields: value, props +func (_m *ProcessorProvider) CreateSignature(value string, props ...*propsmapper.Signature) processorprovider.ProviderComponent { + _va := make([]interface{}, len(props)) + for _i := range props { + _va[_i] = props[_i] + } + var _ca []interface{} + _ca = append(_ca, value) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CreateSignature") + } + + var r0 processorprovider.ProviderComponent + if rf, ok := ret.Get(0).(func(string, ...*propsmapper.Signature) processorprovider.ProviderComponent); ok { + r0 = rf(value, props...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(processorprovider.ProviderComponent) + } + } + + return r0 +} + +// ProcessorProvider_CreateSignature_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateSignature' +type ProcessorProvider_CreateSignature_Call struct { + *mock.Call +} + +// CreateSignature is a helper method to define mock.On call +// - value string +// - props ...*propsmapper.Signature +func (_e *ProcessorProvider_Expecter) CreateSignature(value interface{}, props ...interface{}) *ProcessorProvider_CreateSignature_Call { + return &ProcessorProvider_CreateSignature_Call{Call: _e.mock.On("CreateSignature", + append([]interface{}{value}, props...)...)} +} + +func (_c *ProcessorProvider_CreateSignature_Call) Run(run func(value string, props ...*propsmapper.Signature)) *ProcessorProvider_CreateSignature_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]*propsmapper.Signature, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(*propsmapper.Signature) + } + } + run(args[0].(string), variadicArgs...) + }) + return _c +} + +func (_c *ProcessorProvider_CreateSignature_Call) Return(_a0 processorprovider.ProviderComponent) *ProcessorProvider_CreateSignature_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProcessorProvider_CreateSignature_Call) RunAndReturn(run func(string, ...*propsmapper.Signature) processorprovider.ProviderComponent) *ProcessorProvider_CreateSignature_Call { + _c.Call.Return(run) + return _c +} + +// CreateText provides a mock function with given fields: value, props +func (_m *ProcessorProvider) CreateText(value string, props ...*propsmapper.Text) processorprovider.ProviderComponent { + _va := make([]interface{}, len(props)) + for _i := range props { + _va[_i] = props[_i] + } + var _ca []interface{} + _ca = append(_ca, value) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + if len(ret) == 0 { + panic("no return value specified for CreateText") + } + + var r0 processorprovider.ProviderComponent + if rf, ok := ret.Get(0).(func(string, ...*propsmapper.Text) processorprovider.ProviderComponent); ok { + r0 = rf(value, props...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(processorprovider.ProviderComponent) + } + } + + return r0 +} + +// ProcessorProvider_CreateText_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateText' +type ProcessorProvider_CreateText_Call struct { + *mock.Call +} + +// CreateText is a helper method to define mock.On call +// - value string +// - props ...*propsmapper.Text +func (_e *ProcessorProvider_Expecter) CreateText(value interface{}, props ...interface{}) *ProcessorProvider_CreateText_Call { + return &ProcessorProvider_CreateText_Call{Call: _e.mock.On("CreateText", + append([]interface{}{value}, props...)...)} +} + +func (_c *ProcessorProvider_CreateText_Call) Run(run func(value string, props ...*propsmapper.Text)) *ProcessorProvider_CreateText_Call { + _c.Call.Run(func(args mock.Arguments) { + variadicArgs := make([]*propsmapper.Text, len(args)-1) + for i, a := range args[1:] { + if a != nil { + variadicArgs[i] = a.(*propsmapper.Text) + } + } + run(args[0].(string), variadicArgs...) + }) + return _c +} + +func (_c *ProcessorProvider_CreateText_Call) Return(_a0 processorprovider.ProviderComponent) *ProcessorProvider_CreateText_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProcessorProvider_CreateText_Call) RunAndReturn(run func(string, ...*propsmapper.Text) processorprovider.ProviderComponent) *ProcessorProvider_CreateText_Call { + _c.Call.Return(run) + return _c +} + +// Generate provides a mock function with given fields: +func (_m *ProcessorProvider) Generate() (core.Document, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Generate") + } + + var r0 core.Document + var r1 error + if rf, ok := ret.Get(0).(func() (core.Document, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() core.Document); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(core.Document) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProcessorProvider_Generate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Generate' +type ProcessorProvider_Generate_Call struct { + *mock.Call +} + +// Generate is a helper method to define mock.On call +func (_e *ProcessorProvider_Expecter) Generate() *ProcessorProvider_Generate_Call { + return &ProcessorProvider_Generate_Call{Call: _e.mock.On("Generate")} +} + +func (_c *ProcessorProvider_Generate_Call) Run(run func()) *ProcessorProvider_Generate_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProcessorProvider_Generate_Call) Return(_a0 core.Document, _a1 error) *ProcessorProvider_Generate_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProcessorProvider_Generate_Call) RunAndReturn(run func() (core.Document, error)) *ProcessorProvider_Generate_Call { + _c.Call.Return(run) + return _c +} + +// GetStructure provides a mock function with given fields: +func (_m *ProcessorProvider) GetStructure() *node.Node[core.Structure] { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetStructure") + } + + var r0 *node.Node[core.Structure] + if rf, ok := ret.Get(0).(func() *node.Node[core.Structure]); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*node.Node[core.Structure]) + } + } + + return r0 +} + +// ProcessorProvider_GetStructure_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStructure' +type ProcessorProvider_GetStructure_Call struct { + *mock.Call +} + +// GetStructure is a helper method to define mock.On call +func (_e *ProcessorProvider_Expecter) GetStructure() *ProcessorProvider_GetStructure_Call { + return &ProcessorProvider_GetStructure_Call{Call: _e.mock.On("GetStructure")} +} + +func (_c *ProcessorProvider_GetStructure_Call) Run(run func()) *ProcessorProvider_GetStructure_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProcessorProvider_GetStructure_Call) Return(_a0 *node.Node[core.Structure]) *ProcessorProvider_GetStructure_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProcessorProvider_GetStructure_Call) RunAndReturn(run func() *node.Node[core.Structure]) *ProcessorProvider_GetStructure_Call { + _c.Call.Return(run) + return _c +} + +// NewProcessorProvider creates a new instance of ProcessorProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewProcessorProvider(t interface { + mock.TestingT + Cleanup(func()) +}, +) *ProcessorProvider { + mock := &ProcessorProvider{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/ProcessorRepository.go b/mocks/ProcessorRepository.go new file mode 100644 index 00000000..e1fe28c2 --- /dev/null +++ b/mocks/ProcessorRepository.go @@ -0,0 +1,203 @@ +// Code generated by mockery v2.42.0. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// ProcessorRepository is an autogenerated mock type for the ProcessorRepository type +type ProcessorRepository struct { + mock.Mock +} + +type ProcessorRepository_Expecter struct { + mock *mock.Mock +} + +func (_m *ProcessorRepository) EXPECT() *ProcessorRepository_Expecter { + return &ProcessorRepository_Expecter{mock: &_m.Mock} +} + +// GetDocument provides a mock function with given fields: documentName +func (_m *ProcessorRepository) GetDocument(documentName string) (string, []byte, error) { + ret := _m.Called(documentName) + + if len(ret) == 0 { + panic("no return value specified for GetDocument") + } + + var r0 string + var r1 []byte + var r2 error + if rf, ok := ret.Get(0).(func(string) (string, []byte, error)); ok { + return rf(documentName) + } + if rf, ok := ret.Get(0).(func(string) string); ok { + r0 = rf(documentName) + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func(string) []byte); ok { + r1 = rf(documentName) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).([]byte) + } + } + + if rf, ok := ret.Get(2).(func(string) error); ok { + r2 = rf(documentName) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +// ProcessorRepository_GetDocument_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDocument' +type ProcessorRepository_GetDocument_Call struct { + *mock.Call +} + +// GetDocument is a helper method to define mock.On call +// - documentName string +func (_e *ProcessorRepository_Expecter) GetDocument(documentName interface{}) *ProcessorRepository_GetDocument_Call { + return &ProcessorRepository_GetDocument_Call{Call: _e.mock.On("GetDocument", documentName)} +} + +func (_c *ProcessorRepository_GetDocument_Call) Run(run func(documentName string)) *ProcessorRepository_GetDocument_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *ProcessorRepository_GetDocument_Call) Return(extension string, doc []byte, err error) *ProcessorRepository_GetDocument_Call { + _c.Call.Return(extension, doc, err) + return _c +} + +func (_c *ProcessorRepository_GetDocument_Call) RunAndReturn(run func(string) (string, []byte, error)) *ProcessorRepository_GetDocument_Call { + _c.Call.Return(run) + return _c +} + +// ReadTemplate provides a mock function with given fields: templateName +func (_m *ProcessorRepository) ReadTemplate(templateName string) (map[string]interface{}, error) { + ret := _m.Called(templateName) + + if len(ret) == 0 { + panic("no return value specified for ReadTemplate") + } + + var r0 map[string]interface{} + var r1 error + if rf, ok := ret.Get(0).(func(string) (map[string]interface{}, error)); ok { + return rf(templateName) + } + if rf, ok := ret.Get(0).(func(string) map[string]interface{}); ok { + r0 = rf(templateName) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(map[string]interface{}) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(templateName) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// ProcessorRepository_ReadTemplate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ReadTemplate' +type ProcessorRepository_ReadTemplate_Call struct { + *mock.Call +} + +// ReadTemplate is a helper method to define mock.On call +// - templateName string +func (_e *ProcessorRepository_Expecter) ReadTemplate(templateName interface{}) *ProcessorRepository_ReadTemplate_Call { + return &ProcessorRepository_ReadTemplate_Call{Call: _e.mock.On("ReadTemplate", templateName)} +} + +func (_c *ProcessorRepository_ReadTemplate_Call) Run(run func(templateName string)) *ProcessorRepository_ReadTemplate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *ProcessorRepository_ReadTemplate_Call) Return(_a0 map[string]interface{}, _a1 error) *ProcessorRepository_ReadTemplate_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *ProcessorRepository_ReadTemplate_Call) RunAndReturn(run func(string) (map[string]interface{}, error)) *ProcessorRepository_ReadTemplate_Call { + _c.Call.Return(run) + return _c +} + +// RegisterTemplate provides a mock function with given fields: templateName, template +func (_m *ProcessorRepository) RegisterTemplate(templateName string, template map[string]interface{}) error { + ret := _m.Called(templateName, template) + + if len(ret) == 0 { + panic("no return value specified for RegisterTemplate") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string, map[string]interface{}) error); ok { + r0 = rf(templateName, template) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// ProcessorRepository_RegisterTemplate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RegisterTemplate' +type ProcessorRepository_RegisterTemplate_Call struct { + *mock.Call +} + +// RegisterTemplate is a helper method to define mock.On call +// - templateName string +// - template map[string]interface{} +func (_e *ProcessorRepository_Expecter) RegisterTemplate(templateName interface{}, template interface{}) *ProcessorRepository_RegisterTemplate_Call { + return &ProcessorRepository_RegisterTemplate_Call{Call: _e.mock.On("RegisterTemplate", templateName, template)} +} + +func (_c *ProcessorRepository_RegisterTemplate_Call) Run(run func(templateName string, template map[string]interface{})) *ProcessorRepository_RegisterTemplate_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(map[string]interface{})) + }) + return _c +} + +func (_c *ProcessorRepository_RegisterTemplate_Call) Return(_a0 error) *ProcessorRepository_RegisterTemplate_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProcessorRepository_RegisterTemplate_Call) RunAndReturn(run func(string, map[string]interface{}) error) *ProcessorRepository_RegisterTemplate_Call { + _c.Call.Return(run) + return _c +} + +// NewProcessorRepository creates a new instance of ProcessorRepository. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewProcessorRepository(t interface { + mock.TestingT + Cleanup(func()) +}, +) *ProcessorRepository { + mock := &ProcessorRepository{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/mocks/ProviderComponent.go b/mocks/ProviderComponent.go new file mode 100644 index 00000000..6dd0acc9 --- /dev/null +++ b/mocks/ProviderComponent.go @@ -0,0 +1,120 @@ +// Code generated by mockery v2.42.0. DO NOT EDIT. + +package mocks + +import ( + core "github.com/johnfercher/maroto/v2/pkg/core" + entity "github.com/johnfercher/maroto/v2/pkg/core/entity" + + mock "github.com/stretchr/testify/mock" + + node "github.com/johnfercher/go-tree/node" +) + +// ProviderComponent is an autogenerated mock type for the ProviderComponent type +type ProviderComponent struct { + mock.Mock +} + +type ProviderComponent_Expecter struct { + mock *mock.Mock +} + +func (_m *ProviderComponent) EXPECT() *ProviderComponent_Expecter { + return &ProviderComponent_Expecter{mock: &_m.Mock} +} + +// GetStructure provides a mock function with given fields: +func (_m *ProviderComponent) GetStructure() *node.Node[core.Structure] { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetStructure") + } + + var r0 *node.Node[core.Structure] + if rf, ok := ret.Get(0).(func() *node.Node[core.Structure]); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*node.Node[core.Structure]) + } + } + + return r0 +} + +// ProviderComponent_GetStructure_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetStructure' +type ProviderComponent_GetStructure_Call struct { + *mock.Call +} + +// GetStructure is a helper method to define mock.On call +func (_e *ProviderComponent_Expecter) GetStructure() *ProviderComponent_GetStructure_Call { + return &ProviderComponent_GetStructure_Call{Call: _e.mock.On("GetStructure")} +} + +func (_c *ProviderComponent_GetStructure_Call) Run(run func()) *ProviderComponent_GetStructure_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *ProviderComponent_GetStructure_Call) Return(_a0 *node.Node[core.Structure]) *ProviderComponent_GetStructure_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *ProviderComponent_GetStructure_Call) RunAndReturn(run func() *node.Node[core.Structure]) *ProviderComponent_GetStructure_Call { + _c.Call.Return(run) + return _c +} + +// SetConfig provides a mock function with given fields: config +func (_m *ProviderComponent) SetConfig(config *entity.Config) { + _m.Called(config) +} + +// ProviderComponent_SetConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetConfig' +type ProviderComponent_SetConfig_Call struct { + *mock.Call +} + +// SetConfig is a helper method to define mock.On call +// - config *entity.Config +func (_e *ProviderComponent_Expecter) SetConfig(config interface{}) *ProviderComponent_SetConfig_Call { + return &ProviderComponent_SetConfig_Call{Call: _e.mock.On("SetConfig", config)} +} + +func (_c *ProviderComponent_SetConfig_Call) Run(run func(config *entity.Config)) *ProviderComponent_SetConfig_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*entity.Config)) + }) + return _c +} + +func (_c *ProviderComponent_SetConfig_Call) Return() *ProviderComponent_SetConfig_Call { + _c.Call.Return() + return _c +} + +func (_c *ProviderComponent_SetConfig_Call) RunAndReturn(run func(*entity.Config)) *ProviderComponent_SetConfig_Call { + _c.Call.Return(run) + return _c +} + +// NewProviderComponent creates a new instance of ProviderComponent. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewProviderComponent(t interface { + mock.TestingT + Cleanup(func()) +}, +) *ProviderComponent { + mock := &ProviderComponent{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/processor/core/core.go b/pkg/processor/core/core.go new file mode 100644 index 00000000..82024ad8 --- /dev/null +++ b/pkg/processor/core/core.go @@ -0,0 +1,23 @@ +package core + +type Processor interface { + RegisterTemplate(templateName string, template string) error + GenerateDocument(templateName string, content string) []byte +} + +type ProcessorRepository interface { + RegisterTemplate(templateName string, template map[string]any) error + ReadTemplate(templateName string) (map[string]any, error) + GetDocument(documentName string) (extension string, doc []byte, err error) +} + +type Deserializer interface { + Deserialize(document string) (map[string]interface{}, error) +} + +// Takes a path and returns its bytes +// path may be file path or url +type Loader interface { + Load(path string) ([]byte, error) + GetExt(path string) string +} diff --git a/pkg/processor/deserializer/json_deserializer.go b/pkg/processor/deserializer/json_deserializer.go new file mode 100644 index 00000000..aee74588 --- /dev/null +++ b/pkg/processor/deserializer/json_deserializer.go @@ -0,0 +1,20 @@ +// The deserialize package is responsible for assembling the structures used in the processor according to the receiving string. +package deserializer + +import ( + "encoding/json" +) + +type jsonDeserializer struct{} + +// The new JSONserializer is responsible for creating a json deserializer +func NewJSONDeserializer() *jsonDeserializer { + return &jsonDeserializer{} +} + +// Deserialize is responsible for parsing a json document and creating an interface map +func (j *jsonDeserializer) Deserialize(documentJSON string) (map[string]interface{}, error) { + var document map[string]interface{} + err := json.Unmarshal([]byte(documentJSON), &document) + return document, err +} diff --git a/pkg/processor/loader/loader.go b/pkg/processor/loader/loader.go new file mode 100644 index 00000000..154d82d7 --- /dev/null +++ b/pkg/processor/loader/loader.go @@ -0,0 +1,117 @@ +package loader + +import ( + "io" + "net/http" + "net/url" + "os" + "path/filepath" + "strings" + + "github.com/pkg/errors" +) + +type loader struct{} + +func NewLoader() *loader { + return &loader{} +} + +// GetResourceSource is responsible for identifying where the source resource will be loaded from. +// ex: http, https, file... +func GetResourceSource(path string) (*url.URL, error) { + uri, err := url.Parse(path) + if err != nil { + return nil, errors.Wrap(ErrInvalidPath, path) + } + if uri.Scheme == "" { + uri.Scheme = "file" + } + + return uri, nil +} + +// Load takes the path/url/uri of an asset (image, font) +// and returns its contents. +func (l *loader) Load(path string) ([]byte, error) { + ext := l.GetExt(path) + if _, ok := validExts[ext]; !ok { + return nil, errors.Wrap(ErrUnsupportedExtension, ext) + } + + uri, err := GetResourceSource(path) + if err != nil { + return nil, err + } + + loadFn, ok := loadFuncs[uri.Scheme] + if !ok { + return nil, errors.Wrap(ErrUnsupportedProtocol, uri.Scheme) + } + + r, err := loadFn(uri.String()) + if err != nil { + return nil, errors.Wrap(ErrAccessFail, err.Error()) + } + defer r.Close() + + data, err := io.ReadAll(r) + if err != nil { + return nil, errors.Wrap(ErrReadFail, err.Error()) + } + + return data, nil +} + +func (l *loader) GetExt(path string) string { + toks := strings.Split(path, "?") + toks = strings.Split(toks[0], ".") + if len(toks) < 2 { + return "" + } + return toks[len(toks)-1] +} + +var validExts = map[string]struct{}{ + "png": {}, + "jpg": {}, + "jpeg": {}, + "ttf": {}, +} + +var loadFuncs = map[string]func(string) (io.ReadCloser, error){ + "http": loadHTTP, + "https": loadHTTP, + "file": loadLocal, + "": loadLocal, +} + +func loadLocal(path string) (io.ReadCloser, error) { + path = strings.TrimPrefix(path, "file://") + absolutePath, err := filepath.Abs(path) + if err != nil { + return nil, err + } + f, err := os.Open(absolutePath) + if err != nil { + return nil, err + } + return f, nil +} + +func loadHTTP(path string) (io.ReadCloser, error) { + resp, err := http.Get(path) + if err != nil { + return nil, err + } + + return resp.Body, nil +} + +var ( + ErrUnsupportedProtocol = errors.New("unsupported protocol") + ErrUnsupportedExtension = errors.New("unsupported extension") + ErrInvalidPath = errors.New("invalid path") + ErrAccessFail = errors.New("failed to access asset") + ErrReadFail = errors.New("failed to read asset") +) diff --git a/pkg/processor/loader/loader_test.go b/pkg/processor/loader/loader_test.go new file mode 100644 index 00000000..219e4b52 --- /dev/null +++ b/pkg/processor/loader/loader_test.go @@ -0,0 +1,58 @@ +package loader_test + +import ( + "testing" + + "github.com/johnfercher/maroto/v2/pkg/processor/loader" + "github.com/stretchr/testify/assert" +) + +func TestLoad(t *testing.T) { + t.Run("when invalid extension sent, should return ErrUnsupportedExtension", func(t *testing.T) { + _, err := loader.NewLoader().Load("README.md") + assert.ErrorIs(t, err, loader.ErrUnsupportedExtension) + }) + + t.Run("when invalid path sent, should return ErrInvalidPath", func(t *testing.T) { + _, err := loader.NewLoader().Load("http://hi this is an invalid path.png") + assert.ErrorIs(t, err, loader.ErrInvalidPath) + }) + + t.Run("when path with unsupported protocol sent, should return ErrSupportedProtocol", func(t *testing.T) { + _, err := loader.NewLoader().Load("irc://foobar.com/asset.png") + assert.ErrorIs(t, err, loader.ErrUnsupportedProtocol) + }) + + t.Run("when valid local path sent, should return bytes of file", func(t *testing.T) { + p, err := loader.NewLoader().Load("../../../docs/assets/images/logo.png") + assert.NoError(t, err) + assert.NotNil(t, p) + }) + + t.Run("when valid file uri sent, should return bytes of file", func(t *testing.T) { + p, err := loader.NewLoader().Load("file://../../../docs/assets/images/logo.png") + assert.NoError(t, err) + assert.NotNil(t, p) + }) + + t.Run("when valid network path sent, should return bytes of asset", func(t *testing.T) { + p, err := loader.NewLoader().Load("https://github.com/johnfercher/maroto/blob/master/docs/assets/images/biplane.jpg?raw=true") + assert.NoError(t, err) + assert.NotNil(t, p) + }) +} + +func TestGetResourceSource(t *testing.T) { + t.Run("when a local path is sent, should return a uri with shema file", func(t *testing.T) { + uri, err := loader.GetResourceSource("file://docs/assets/images/logo.png") + + assert.Nil(t, err) + assert.Equal(t, uri.Scheme, "file") + }) + t.Run("when a path without shema is sent, should return a uri with shema file", func(t *testing.T) { + uri, err := loader.GetResourceSource("docs/assets/images/logo.png") + + assert.Nil(t, err) + assert.Equal(t, uri.Scheme, "file") + }) +} diff --git a/pkg/processor/mappers/abstractfactory/abstractfactory.go b/pkg/processor/mappers/abstractfactory/abstractfactory.go new file mode 100644 index 00000000..6cf51daa --- /dev/null +++ b/pkg/processor/mappers/abstractfactory/abstractfactory.go @@ -0,0 +1,81 @@ +package abstractfactory + +import ( + "github.com/johnfercher/maroto/v2/pkg/processor/core" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/codemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/colmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/imagemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/linemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/listmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/pagemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/rowmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/signaturemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/textmapper" +) + +type abstractFactoryMaps struct { + repository core.ProcessorRepository +} + +// NewAbstractFactoryMaps is responsible for creating an object that encapsulates the creation of components +func NewAbstractFactoryMaps(repository core.ProcessorRepository) *abstractFactoryMaps { + return &abstractFactoryMaps{repository: repository} +} + +// NewRow is responsible for wrapper the creation of a row +func (f *abstractFactoryMaps) NewRow(document interface{}, sourceKey string) (mappers.OrderedComponents, error) { + return rowmapper.NewRow(document, sourceKey, f) +} + +// NewPage is responsible for wrapper the creation of a page +func (f *abstractFactoryMaps) NewPage(document interface{}, sourceKey string) (mappers.OrderedComponents, error) { + return pagemapper.NewPage(document, sourceKey, f) +} + +// NewCol is responsible for wrapper the creation of a col +func (f *abstractFactoryMaps) NewCol(document interface{}) (mappers.Componentmapper, error) { + return colmapper.NewCol(document, f) +} + +// NewList is responsible for wrapper the creation of a list +func (f *abstractFactoryMaps) NewList(document interface{}, sourceKey string, + generate mappers.GenerateComponent, +) (mappers.OrderedComponents, error) { + return listmapper.NewList(document, sourceKey, generate) +} + +// NewBarcode is responsible for wrapper the creation of a barcode +func (f *abstractFactoryMaps) NewBarcode(document interface{}) (mappers.OrderedComponents, error) { + return codemapper.NewBarcode(document) +} + +// NewMatrixcode is responsible for wrapper the creation of a matrix code +func (f *abstractFactoryMaps) NewMatrixcode(document interface{}) (mappers.OrderedComponents, error) { + return codemapper.NewMatrixcode(document) +} + +// NewQrcode is responsible for wrapper the creation of a qrcode +func (f *abstractFactoryMaps) NewQrcode(document interface{}) (mappers.OrderedComponents, error) { + return codemapper.NewQrcode(document) +} + +// NewImage is responsible for wrapper the creation of a image +func (f *abstractFactoryMaps) NewImage(document interface{}) (mappers.OrderedComponents, error) { + return imagemapper.NewImage(document) +} + +// NewLine is responsible for wrapper the creation of a libe +func (f *abstractFactoryMaps) NewLine(document interface{}) (mappers.OrderedComponents, error) { + return linemapper.NewLine(document) +} + +// NewSignature is responsible for wrapper the creation of a signature +func (f *abstractFactoryMaps) NewSignature(document interface{}) (mappers.OrderedComponents, error) { + return signaturemapper.NewSignature(document) +} + +// NewText is responsible for wrapper the creation of a text +func (f *abstractFactoryMaps) NewText(document interface{}) (mappers.OrderedComponents, error) { + return textmapper.NewText(document) +} diff --git a/pkg/processor/mappers/buildermapper/builder.go b/pkg/processor/mappers/buildermapper/builder.go new file mode 100644 index 00000000..9febb6de --- /dev/null +++ b/pkg/processor/mappers/buildermapper/builder.go @@ -0,0 +1,65 @@ +package buildermapper + +import ( + "fmt" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" +) + +type Builder struct { + PageSize string + Dimensions *propsmapper.Dimensions + Margins *propsmapper.Margins + ConcurrentMode int + SequentialMode bool + SequentialLowMemoryMode int + Debug bool + MaxGridSize int + DefaultFont *propsmapper.Font + CustomFonts []*propsmapper.CustomFont + PageNumber *propsmapper.PageNumber + Protection *propsmapper.Protection + Compression bool + Orientation string + Metadata *propsmapper.Metadata + DisableAutoPageBreak bool + GenerationMode string + BackgroundImage string +} + +// NewBuilder is responsible for creating Builder properties. If an invalid property is provided, a default value will be assigned. +func NewBuilder(builder interface{}) (*Builder, error) { + builderMap, ok := builder.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("builder settings could not be deserialized") + } + + return &Builder{ + PageSize: factoryField(builderMap["page_size"], ""), + Dimensions: propsmapper.NewDimensions(builderMap["dimensions"]), + Margins: propsmapper.NewMargins(builderMap["margins"]), + ConcurrentMode: int(factoryField(builderMap["concurrent_mode"], -1.0)), + SequentialMode: factoryField(builderMap["sequential_mode"], false), + SequentialLowMemoryMode: int(factoryField(builderMap["sequential_low_memory_mode"], -1.0)), + Debug: factoryField(builderMap["debug"], false), + MaxGridSize: int(factoryField(builderMap["max_grid_size"], -1.0)), + DefaultFont: propsmapper.NewFont(builderMap["default_font"]), + CustomFonts: propsmapper.NewCustomFonts(builderMap["custom_fonts"]), + PageNumber: propsmapper.NewPageNumber(builderMap["page_number"]), + Protection: propsmapper.NewProtection(builderMap["protection"]), + Compression: factoryField(builderMap["compression"], false), + Orientation: propsmapper.NewOrientation(factoryField(builderMap["orientation"], "")), + Metadata: propsmapper.NewMetadata(builderMap["metadata"]), + DisableAutoPageBreak: factoryField(builderMap["disable_auto_page_break"], false), + GenerationMode: factoryField(builderMap["generation_mode"], ""), + BackgroundImage: factoryField(builderMap["background_image"], ""), + }, nil +} + +func factoryField[T any](val interface{}, defaultValue T) T { + result, ok := val.(T) + if !ok { + return defaultValue + } + return result +} diff --git a/pkg/processor/mappers/buildermapper/bulder_test.go b/pkg/processor/mappers/buildermapper/bulder_test.go new file mode 100644 index 00000000..26b58b9d --- /dev/null +++ b/pkg/processor/mappers/buildermapper/bulder_test.go @@ -0,0 +1,127 @@ +package buildermapper + +import ( + "encoding/json" + "testing" + "time" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/test" + "github.com/stretchr/testify/assert" +) + +func DefaultBuilderMap() *Builder { + time, _ := time.Parse("2006-01-02 15:04:05", "2024-10-09 14:30:00") + return &Builder{ + Dimensions: &propsmapper.Dimensions{ + Width: 10.0, + Height: 10.0, + }, + Margins: &propsmapper.Margins{ + Left: 10.0, + Right: 10.0, + Top: 10.0, + Bottom: 10.0, + }, + SequentialMode: false, + ConcurrentMode: 10, + SequentialLowMemoryMode: -1, + Debug: true, + MaxGridSize: 10, + DefaultFont: &propsmapper.Font{ + Family: "Arial", + Style: "B", + Size: 10, + Color: &propsmapper.Color{ + Red: 10, + Green: 100, + Blue: 150, + }, + }, + PageNumber: &propsmapper.PageNumber{ + Pattern: "pattern_test", + Place: "place_test", + Family: "family_test", + Style: "I", + Size: 10.0, + Color: &propsmapper.Color{ + Red: 10, + Green: 100, + Blue: 150, + }, + }, + CustomFonts: []*propsmapper.CustomFont{ + {Family: "family_test", Style: "B", File: "file_test"}, + {Family: "family_test2", Style: "B", File: "file_test2"}, + }, + Protection: &propsmapper.Protection{ + Type: 4, + UserPassword: "senha123", + OwnerPassword: "senha123", + }, + Compression: true, + PageSize: "T", + Orientation: "vertical", + Metadata: &propsmapper.Metadata{ + Author: &propsmapper.Utf8Text{Text: "user_test", UTF8: true}, + Creator: &propsmapper.Utf8Text{Text: "user_test", UTF8: true}, + Subject: &propsmapper.Utf8Text{Text: "test", UTF8: true}, + Title: &propsmapper.Utf8Text{Text: "report", UTF8: true}, + CreationDate: &time, + KeywordsStr: &propsmapper.Utf8Text{Text: "test", UTF8: true}, + }, + DisableAutoPageBreak: true, + GenerationMode: "concurrent", + } +} + +func TestNewBuilder(t *testing.T) { + t.Run("when all builder properties are sent, it should generate the builder with all props", func(t *testing.T) { + builderMap := DefaultBuilderMap() + file, _ := test.NewFileReader().LoadFile("processor/all_builder_pros.json") + + var builderInterface interface{} + if err := json.Unmarshal(file, &builderInterface); err != nil { + t.Error("could not deserialize json") + return + } + + generateBuilder, err := NewBuilder(builderInterface) + assert.Nil(t, err) + assert.Equal(t, *builderMap, *generateBuilder) + }) + + t.Run("when props is not sent, it should use deafault props", func(t *testing.T) { + file, _ := test.NewFileReader().LoadFile("processor/without_all_builder_props.json") + const defaultDimensions = -1.0 + + var builderInterface interface{} + if err := json.Unmarshal(file, &builderInterface); err != nil { + t.Error("could not deserialize json") + return + } + + generateBuilder, err := NewBuilder(builderInterface) + assert.Nil(t, err) + assert.Equal(t, defaultDimensions, generateBuilder.Dimensions.Width) + }) + + t.Run("when no builder props is sent, no error is returned", func(t *testing.T) { + file, _ := test.NewFileReader().LoadFile("processor/without_builder_props.json") + + var builderInterface interface{} + if err := json.Unmarshal(file, &builderInterface); err != nil { + t.Error("could not deserialize json") + return + } + _, err := NewBuilder(builderInterface) + assert.Nil(t, err) + }) + + t.Run("when an invalid Builder is sent, it should return an error", func(t *testing.T) { + var builderInterface interface{} = 1 + + _, err := NewBuilder(builderInterface) + assert.NotNil(t, err) + }) +} diff --git a/pkg/processor/mappers/component_mapper.go b/pkg/processor/mappers/component_mapper.go new file mode 100644 index 00000000..f0e39852 --- /dev/null +++ b/pkg/processor/mappers/component_mapper.go @@ -0,0 +1,37 @@ +package mappers + +import ( + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" +) + +// GenerateComponent defines the signature of a factory method, it is used +// to make it possible to send a factory method to another object +type GenerateComponent func(document interface{}, sourceKey string) (OrderedComponents, error) + +// The Component Mapper Interface defines the mapper component, the mapper component is responsible for +// transforming the structured document into the pdf components +type Componentmapper interface { + Generate(content map[string]interface{}, provider processorprovider.ProcessorProvider) ([]processorprovider.ProviderComponent, error) +} + +// The ordered component interface defines an component that needs to be ordered by parent component +type OrderedComponents interface { + Componentmapper + GetOrder() int +} + +// The AbstractFactoryMaps interface defines the object responsible for wrapping the creation of components +// it is used to ensure decoupling between components +type AbstractFactoryMaps interface { + NewRow(document interface{}, sourceKey string) (OrderedComponents, error) + NewPage(document interface{}, sourceKey string) (OrderedComponents, error) + NewCol(document interface{}) (Componentmapper, error) + NewList(document interface{}, sourceKey string, generate GenerateComponent) (OrderedComponents, error) + NewBarcode(document interface{}) (OrderedComponents, error) + NewMatrixcode(document interface{}) (OrderedComponents, error) + NewQrcode(document interface{}) (OrderedComponents, error) + NewImage(document interface{}) (OrderedComponents, error) + NewLine(document interface{}) (OrderedComponents, error) + NewSignature(document interface{}) (OrderedComponents, error) + NewText(document interface{}) (OrderedComponents, error) +} diff --git a/pkg/processor/mappers/components/codemapper/barcode.go b/pkg/processor/mappers/components/codemapper/barcode.go new file mode 100644 index 00000000..100697e2 --- /dev/null +++ b/pkg/processor/mappers/components/codemapper/barcode.go @@ -0,0 +1,139 @@ +// codemapper code implements creation of Barcode, MatrixCode and QrCode. +// nolint:dupl +package codemapper + +import ( + "fmt" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/order" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" +) + +type Barcode struct { + SourceKey string + Code string + Props *propsmapper.Barcode + Order int +} + +func NewBarcode(code interface{}) (*Barcode, error) { + barcodeMap, ok := code.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure barcode can be converted to map[string] interface{}") + } + + barcode := &Barcode{} + if err := barcode.addFields(barcodeMap); err != nil { + return nil, err + } + if err := barcode.validateFields(); err != nil { + return nil, err + } + + return barcode, nil +} + +// addFields is responsible for adding the barcode fields according to +// the properties informed in the map +func (b *Barcode) addFields(codeMap map[string]interface{}) error { + order, err := order.SetPageOrder(&codeMap, "barcode", b.SourceKey) + if err != nil { + return err + } + b.Order = order + + fieldMappers := b.getFieldMappers() + + for templateName, template := range codeMap { + mapper, ok := fieldMappers[templateName] + if !ok { + return fmt.Errorf("the field %s present in the barcode cannot be mapped to any valid field", templateName) + } + err := mapper(template) + if err != nil { + return err + } + } + return nil +} + +// GetOrder is responsible for returning the component's defined order +func (b *Barcode) GetOrder() int { + return b.Order +} + +// getFieldMappers is responsible for defining which methods are responsible for assembling which components. +// To do this, the component name is linked to a function in a Map. +func (b *Barcode) getFieldMappers() map[string]func(interface{}) error { + return map[string]func(interface{}) error{ + "source_key": b.setSourceKey, + "value": b.setCode, + "props": b.setProps, + } +} + +func (b *Barcode) setSourceKey(template interface{}) error { + sourceKey, ok := template.(string) + if !ok { + return fmt.Errorf("source_key cannot be converted to a string") + } + b.SourceKey = sourceKey + return nil +} + +func (b *Barcode) setCode(template interface{}) error { + code, ok := template.(string) + if !ok { + return fmt.Errorf("code cannot be converted to a string") + } + b.Code = code + return nil +} + +func (b *Barcode) setProps(template interface{}) error { + props, err := propsmapper.NewBarcode(template) + if err != nil { + return err + } + b.Props = props + return nil +} + +func (b *Barcode) validateFields() error { + if b.Code == "" && b.SourceKey == "" { + return fmt.Errorf("no value passed for barcode. Add the 'source_key' or a code") + } + return nil +} + +func (b *Barcode) getCode(content map[string]interface{}) (string, error) { + if b.Code != "" { + return b.Code, nil + } + codeFound, ok := content[b.SourceKey] + if !ok { + return "", fmt.Errorf("barcode requires a source key named %s, but it was not found", b.SourceKey) + } + codeValid, ok := codeFound.(string) + if !ok { + return "", fmt.Errorf("unable to generate barcode, invalid code. source key %s", b.SourceKey) + } + return codeValid, nil +} + +// Generate is responsible for computing the page component with shipping data +func (b *Barcode) Generate(content map[string]interface{}, provider processorprovider.ProcessorProvider) ( + []processorprovider.ProviderComponent, error, +) { + code, err := b.getCode(content) + if err != nil { + return nil, err + } + b.Code = code + + if b.Props != nil { + return []processorprovider.ProviderComponent{provider.CreateBarCode(b.Code, b.Props)}, nil + } + return []processorprovider.ProviderComponent{provider.CreateBarCode(b.Code)}, nil +} diff --git a/pkg/processor/mappers/components/codemapper/barcode_test.go b/pkg/processor/mappers/components/codemapper/barcode_test.go new file mode 100644 index 00000000..31620273 --- /dev/null +++ b/pkg/processor/mappers/components/codemapper/barcode_test.go @@ -0,0 +1,174 @@ +// nolint:dupl +package codemapper_test + +import ( + "testing" + + "github.com/johnfercher/maroto/v2/mocks" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/codemapper" + "github.com/stretchr/testify/assert" +) + +func TestBarcodeGetOrder(t *testing.T) { + t.Run("when getOrder is called, should return defined order", func(t *testing.T) { + templateRows := map[string]interface{}{ + "order": 10.0, + "value": "test", + } + + doc, err := codemapper.NewBarcode(templateRows) + + assert.Nil(t, err) + assert.Equal(t, 10, doc.GetOrder()) + }) +} + +func TestNewBarcode(t *testing.T) { + t.Run("when invalid barcode is sent, should return an error", func(t *testing.T) { + barcodeTemplate := 1 + + barcode, err := codemapper.NewMatrixcode(barcodeTemplate) + + assert.Nil(t, barcode) + assert.NotNil(t, err) + }) + t.Run("when props is not sent, barcode is created", func(t *testing.T) { + barcodeTemplate := map[string]interface{}{ + "value": "123456789", + "order": 1.0, + } + + barcode, err := codemapper.NewBarcode(barcodeTemplate) + + assert.Nil(t, err) + assert.NotNil(t, barcode) + }) + t.Run("when invalid props is sent, should return an error", func(t *testing.T) { + barcodeTemplate := map[string]interface{}{ + "props": 1, + "value": "123456789", + "order": 1.0, + } + + barcode, err := codemapper.NewBarcode(barcodeTemplate) + + assert.Nil(t, barcode) + assert.NotNil(t, err) + }) + t.Run("when invalid field is sent, should return an error", func(t *testing.T) { + barcodeTemplate := map[string]interface{}{ + "invalid_field": 1, + "value": "123456789", + "order": 1.0, + } + + barcode, err := codemapper.NewBarcode(barcodeTemplate) + + assert.Nil(t, barcode) + assert.NotNil(t, err) + }) + t.Run("when source_key and code are not sent, should return an error", func(t *testing.T) { + barcodeTemplate := map[string]interface{}{} + + barcode, err := codemapper.NewBarcode(barcodeTemplate) + + assert.Nil(t, barcode) + assert.NotNil(t, err) + }) + t.Run("when invalid code is sent, should return an error", func(t *testing.T) { + barcodeTemplate := map[string]interface{}{ + "value": 123, + "order": 1.0, + } + + barcode, err := codemapper.NewBarcode(barcodeTemplate) + + assert.Nil(t, barcode) + assert.NotNil(t, err) + }) + t.Run("when invalid source_key is sent, should return an error", func(t *testing.T) { + barcodeTemplate := map[string]interface{}{ + "source_key": 123, + "order": 1.0, + } + + barcode, err := codemapper.NewBarcode(barcodeTemplate) + + assert.Nil(t, barcode) + assert.NotNil(t, err) + }) + t.Run("when code is not sent, should add source key", func(t *testing.T) { + barcodeTemplate := map[string]interface{}{ + "source_key": "source", + "order": 1.0, + } + + barcode, err := codemapper.NewBarcode(barcodeTemplate) + + assert.Nil(t, err) + assert.Equal(t, barcode.SourceKey, "source") + }) + + t.Run("when source_key is not sent, should add code", func(t *testing.T) { + barcodeTemplate := map[string]interface{}{ + "value": "code", + "order": 1.0, + } + + barcode, err := codemapper.NewBarcode(barcodeTemplate) + + assert.Nil(t, err) + assert.Equal(t, barcode.Code, "code") + }) +} + +func TestGenerate(t *testing.T) { + t.Run("if source key is not found, should return an error", func(t *testing.T) { + content := map[string]interface{}{} + provider := mocks.NewProcessorProvider(t) + + barcode := codemapper.Barcode{SourceKey: "code"} + component, err := barcode.Generate(content, provider) + + assert.Nil(t, component) + assert.NotNil(t, err) + }) + t.Run("if source key content is not valid, should return an error", func(t *testing.T) { + content := map[string]interface{}{ + "code": 1, + } + provider := mocks.NewProcessorProvider(t) + + barcode := codemapper.Barcode{SourceKey: "code"} + component, err := barcode.Generate(content, provider) + + assert.Nil(t, component) + assert.NotNil(t, err) + }) + t.Run("If the barcode has no props, the props will not be sent", func(t *testing.T) { + content := map[string]interface{}{ + "code": "code", + } + + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateBarCode("code").Return(nil) + + barcode := codemapper.Barcode{SourceKey: "code"} + _, err := barcode.Generate(content, provider) + + assert.Nil(t, err) + provider.AssertNumberOfCalls(t, "CreateBarCode", 1) + }) + t.Run("when valid code is sent, should generate barcode", func(t *testing.T) { + content := map[string]interface{}{} + + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateBarCode("code").Return(nil) + + barcode := codemapper.Barcode{Code: "code"} + _, err := barcode.Generate(content, provider) + + assert.Nil(t, err) + provider.AssertNumberOfCalls(t, "CreateBarCode", 1) + }) +} diff --git a/pkg/processor/mappers/components/codemapper/matrixcode.go b/pkg/processor/mappers/components/codemapper/matrixcode.go new file mode 100644 index 00000000..ffbc9cef --- /dev/null +++ b/pkg/processor/mappers/components/codemapper/matrixcode.go @@ -0,0 +1,137 @@ +// Package codemapper implements creation of matrixCode, MatrixCode and QrCode. +// nolint:dupl +package codemapper + +import ( + "fmt" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/order" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" +) + +type Matrixcode struct { + SourceKey string + Code string + Props *propsmapper.Rect + Order int +} + +func NewMatrixcode(code interface{}) (*Matrixcode, error) { + matrixcodeMap, ok := code.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure matrixcode can be converted to map[string] interface{}") + } + + matrixCode := &Matrixcode{} + if err := matrixCode.addFields(matrixcodeMap); err != nil { + return nil, err + } + if err := matrixCode.validateFields(); err != nil { + return nil, err + } + + return matrixCode, nil +} + +// addFields is responsible for adding the matrix code fields according to +// the properties informed in the map +func (m *Matrixcode) addFields(codeMap map[string]interface{}) error { + order, err := order.SetPageOrder(&codeMap, "matrixcode", m.SourceKey) + if err != nil { + return err + } + m.Order = order + fieldMappers := m.getFieldMappers() + + for templateName, template := range codeMap { + mapper, ok := fieldMappers[templateName] + if !ok { + return fmt.Errorf("the field %s present in the matrix code cannot be mapped to any valid field", templateName) + } + err := mapper(template) + if err != nil { + return err + } + } + return nil +} + +// GetOrder is responsible for returning the component's defined order +func (m *Matrixcode) GetOrder() int { + return m.Order +} + +// getFieldMappers is responsible for defining which methods are responsible for assembling which components. +// To do this, the component name is linked to a function in a Map. +func (m *Matrixcode) getFieldMappers() map[string]func(interface{}) error { + return map[string]func(interface{}) error{ + "source_key": m.setSourceKey, + "value": m.setCode, + "props": m.setProps, + } +} + +func (m *Matrixcode) setSourceKey(template interface{}) error { + sourceKey, ok := template.(string) + if !ok { + return fmt.Errorf("source_key cannot be converted to a string") + } + m.SourceKey = sourceKey + return nil +} + +func (m *Matrixcode) setCode(template interface{}) error { + code, ok := template.(string) + if !ok { + return fmt.Errorf("code cannot be converted to a string") + } + m.Code = code + return nil +} + +func (m *Matrixcode) setProps(template interface{}) error { + props, err := propsmapper.NewRect(template) + if err != nil { + return err + } + m.Props = props + return nil +} + +func (m *Matrixcode) validateFields() error { + if m.Code == "" && m.SourceKey == "" { + return fmt.Errorf("no value passed for matrixCode. Add the 'source_key' or a code") + } + return nil +} + +func (m *Matrixcode) getCode(content map[string]interface{}) (string, error) { + if m.Code != "" { + return m.Code, nil + } + codeFound, ok := content[m.SourceKey] + if !ok { + return "", fmt.Errorf("matrixcode requires a source key named %s, but it was not found", m.SourceKey) + } + codeValid, ok := codeFound.(string) + if !ok { + return "", fmt.Errorf("unable to generate matrixcode, invalid code. source key %s", m.SourceKey) + } + return codeValid, nil +} + +func (m *Matrixcode) Generate(content map[string]interface{}, provider processorprovider.ProcessorProvider) ( + []processorprovider.ProviderComponent, error, +) { + code, err := m.getCode(content) + if err != nil { + return nil, err + } + m.Code = code + + if m.Props != nil { + return []processorprovider.ProviderComponent{provider.CreateMatrixCode(m.Code, m.Props)}, nil + } + return []processorprovider.ProviderComponent{provider.CreateMatrixCode(m.Code)}, nil +} diff --git a/pkg/processor/mappers/components/codemapper/matrixcode_test.go b/pkg/processor/mappers/components/codemapper/matrixcode_test.go new file mode 100644 index 00000000..be38ff6f --- /dev/null +++ b/pkg/processor/mappers/components/codemapper/matrixcode_test.go @@ -0,0 +1,181 @@ +// nolint:dupl +package codemapper_test + +import ( + "testing" + + "github.com/johnfercher/maroto/v2/mocks" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/codemapper" + "github.com/stretchr/testify/assert" +) + +func TestMatrixCodeGetOrder(t *testing.T) { + t.Run("when getOrder is called, should return defined order", func(t *testing.T) { + templateRows := map[string]interface{}{ + "order": 10.0, + "value": "code", + } + + doc, _ := codemapper.NewMatrixcode(templateRows) + + assert.Equal(t, 10, doc.GetOrder()) + }) +} + +func TestNewMatrixcode(t *testing.T) { + t.Run("when invalid matrixcode is sent, should return an error", func(t *testing.T) { + matrixcodeTemplate := 1 + + matrixcode, err := codemapper.NewMatrixcode(matrixcodeTemplate) + + assert.Nil(t, matrixcode) + assert.NotNil(t, err) + }) + t.Run("when props is not sent, matrixcode is created", func(t *testing.T) { + matrixcodeTemplate := map[string]interface{}{ + "order": 1.0, + "value": "123456789", + } + + matrixcode, err := codemapper.NewMatrixcode(matrixcodeTemplate) + + assert.Nil(t, err) + assert.NotNil(t, matrixcode) + }) + t.Run("when invalid props is sent, should return an error", func(t *testing.T) { + matrixcodeTemplate := map[string]interface{}{ + "order": 1.0, + "props": 1, + "code": "123456789", + } + + matrixcode, err := codemapper.NewMatrixcode(matrixcodeTemplate) + + assert.Nil(t, matrixcode) + assert.NotNil(t, err) + }) + t.Run("when invalid field is sent, should return an error", func(t *testing.T) { + matrixcodeTemplate := map[string]interface{}{ + "order": 1.0, + "invalid_field": 1, + "code": "123456789", + } + + matrixcode, err := codemapper.NewMatrixcode(matrixcodeTemplate) + + assert.Nil(t, matrixcode) + assert.NotNil(t, err) + }) + t.Run("when source_key and code are not sent, should return an error", func(t *testing.T) { + matrixcodeTemplate := map[string]interface{}{ + "order": 1.0, + } + + matrixcode, err := codemapper.NewMatrixcode(matrixcodeTemplate) + + assert.Nil(t, matrixcode) + assert.NotNil(t, err) + }) + t.Run("when invalid code is sent, should return an error", func(t *testing.T) { + matrixcodeTemplate := map[string]interface{}{ + "order": 1.0, + "value": 123, + } + + matrixcode, err := codemapper.NewMatrixcode(matrixcodeTemplate) + + assert.Nil(t, matrixcode) + assert.NotNil(t, err) + }) + t.Run("when invalid source_key is sent, should return an error", func(t *testing.T) { + matrixcodeTemplate := map[string]interface{}{ + "order": 1.0, + "source_key": 123, + } + + matrixcode, err := codemapper.NewMatrixcode(matrixcodeTemplate) + + assert.Nil(t, matrixcode) + assert.NotNil(t, err) + }) + t.Run("when code is not sent, should add source key", func(t *testing.T) { + matrixcodeTemplate := map[string]interface{}{ + "order": 1.0, + "source_key": "source", + } + + matrixcode, err := codemapper.NewMatrixcode(matrixcodeTemplate) + + assert.Nil(t, err) + assert.Equal(t, matrixcode.SourceKey, "source") + }) + + t.Run("when source_key is not sent, should add code", func(t *testing.T) { + matrixcodeTemplate := map[string]interface{}{ + "order": 1.0, + "value": "code", + } + + matrixcode, err := codemapper.NewMatrixcode(matrixcodeTemplate) + + assert.Nil(t, err) + assert.Equal(t, matrixcode.Code, "code") + }) +} + +func TestMatrixcodeGenerate(t *testing.T) { + t.Run("if source key is not found, should return an error", func(t *testing.T) { + content := map[string]interface{}{ + "order": 1.0, + } + provider := mocks.NewProcessorProvider(t) + + matrixcode := codemapper.Matrixcode{SourceKey: "code"} + component, err := matrixcode.Generate(content, provider) + + assert.Nil(t, component) + assert.NotNil(t, err) + }) + t.Run("if source key content is not valid, should return an error", func(t *testing.T) { + content := map[string]interface{}{ + "order": 1.0, + "code": 1, + } + provider := mocks.NewProcessorProvider(t) + + matrixcode := codemapper.Matrixcode{SourceKey: "code"} + component, err := matrixcode.Generate(content, provider) + + assert.Nil(t, component) + assert.NotNil(t, err) + }) + t.Run("If the matrixcode has no props, the props will not be sent", func(t *testing.T) { + content := map[string]interface{}{ + "order": 1.0, + "code": "code", + } + + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateMatrixCode("code").Return(nil) + + matrixcode := codemapper.Matrixcode{SourceKey: "code"} + _, err := matrixcode.Generate(content, provider) + + assert.Nil(t, err) + provider.AssertNumberOfCalls(t, "CreateMatrixCode", 1) + }) + t.Run("when valid code is sent, should generate matrixcode", func(t *testing.T) { + content := map[string]interface{}{ + "order": 1.0, + } + + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateMatrixCode("code").Return(nil) + + matrixcode := codemapper.Matrixcode{Code: "code"} + _, err := matrixcode.Generate(content, provider) + + assert.Nil(t, err) + provider.AssertNumberOfCalls(t, "CreateMatrixCode", 1) + }) +} diff --git a/pkg/processor/mappers/components/codemapper/qrcode.go b/pkg/processor/mappers/components/codemapper/qrcode.go new file mode 100644 index 00000000..e20db41f --- /dev/null +++ b/pkg/processor/mappers/components/codemapper/qrcode.go @@ -0,0 +1,138 @@ +// Package codemapper implements creation of qrcode, MatrixCode and QrCode. +// nolint:dupl +package codemapper + +import ( + "fmt" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/order" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" +) + +type Qrcode struct { + SourceKey string + Code string + Props *propsmapper.Rect + Order int +} + +func NewQrcode(code interface{}) (*Qrcode, error) { + qrcodeMap, ok := code.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure qrcode can be converted to map[string] interface{}") + } + + qrcode := &Qrcode{} + if err := qrcode.addFields(qrcodeMap); err != nil { + return nil, err + } + if err := qrcode.validateFields(); err != nil { + return nil, err + } + + return qrcode, nil +} + +// addFields is responsible for adding the qrcode fields according to +// the properties informed in the map +func (q *Qrcode) addFields(codeMap map[string]interface{}) error { + order, err := order.SetPageOrder(&codeMap, "qrcode", q.SourceKey) + if err != nil { + return err + } + q.Order = order + + fieldMappers := q.getFieldMappers() + + for templateName, template := range codeMap { + mapper, ok := fieldMappers[templateName] + if !ok { + return fmt.Errorf("the field %s present in the qrcode cannot be mapped to any valid field", templateName) + } + err := mapper(template) + if err != nil { + return err + } + } + return nil +} + +// GetOrder is responsible for returning the component's defined order +func (q *Qrcode) GetOrder() int { + return q.Order +} + +// getFieldMappers is responsible for defining which methods are responsible for assembling which components. +// To do this, the component name is linked to a function in a Map. +func (q *Qrcode) getFieldMappers() map[string]func(interface{}) error { + return map[string]func(interface{}) error{ + "source_key": q.setSourceKey, + "value": q.setCode, + "props": q.setProps, + } +} + +func (q *Qrcode) setSourceKey(template interface{}) error { + sourceKey, ok := template.(string) + if !ok { + return fmt.Errorf("source_key cannot be converted to a string") + } + q.SourceKey = sourceKey + return nil +} + +func (q *Qrcode) setCode(template interface{}) error { + code, ok := template.(string) + if !ok { + return fmt.Errorf("code cannot be converted to a string") + } + q.Code = code + return nil +} + +func (q *Qrcode) setProps(template interface{}) error { + props, err := propsmapper.NewRect(template) + if err != nil { + return err + } + q.Props = props + return nil +} + +func (q *Qrcode) validateFields() error { + if q.Code == "" && q.SourceKey == "" { + return fmt.Errorf("no value passed for qrcode. Add the 'source_key' or a code") + } + return nil +} + +func (q *Qrcode) getCode(content map[string]interface{}) (string, error) { + if q.Code != "" { + return q.Code, nil + } + codeFound, ok := content[q.SourceKey] + if !ok { + return "", fmt.Errorf("qrcode requires a source key named %s, but it was not found", q.SourceKey) + } + codeValid, ok := codeFound.(string) + if !ok { + return "", fmt.Errorf("unable to generate qrcode, invalid code. source key %s", q.SourceKey) + } + return codeValid, nil +} + +func (q *Qrcode) Generate(content map[string]interface{}, provider processorprovider.ProcessorProvider) ( + []processorprovider.ProviderComponent, error, +) { + code, err := q.getCode(content) + if err != nil { + return nil, err + } + q.Code = code + + if q.Props != nil { + return []processorprovider.ProviderComponent{provider.CreateQrCode(q.Code, q.Props)}, nil + } + return []processorprovider.ProviderComponent{provider.CreateQrCode(q.Code)}, nil +} diff --git a/pkg/processor/mappers/components/codemapper/qrcode_test.go b/pkg/processor/mappers/components/codemapper/qrcode_test.go new file mode 100644 index 00000000..409c5bc6 --- /dev/null +++ b/pkg/processor/mappers/components/codemapper/qrcode_test.go @@ -0,0 +1,173 @@ +// nolint:dupl +package codemapper_test + +import ( + "testing" + + "github.com/johnfercher/maroto/v2/mocks" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/codemapper" + "github.com/stretchr/testify/assert" +) + +func TestQrcodeGetOrder(t *testing.T) { + t.Run("when getOrder is called, should return defined order", func(t *testing.T) { + templateRows := map[string]interface{}{ + "order": 10.0, + "value": "code", + } + + doc, _ := codemapper.NewBarcode(templateRows) + + assert.Equal(t, 10, doc.GetOrder()) + }) +} + +func TestNewQrCode(t *testing.T) { + t.Run("when invalid qrcode is sent, should return an error", func(t *testing.T) { + qrcodeTemplate := 1 + + qrcode, err := codemapper.NewQrcode(qrcodeTemplate) + + assert.Nil(t, qrcode) + assert.NotNil(t, err) + }) + t.Run("when props is not sent, should create qrcode", func(t *testing.T) { + qrcodeTemplate := map[string]interface{}{ + "order": 1.0, + "value": "123456789", + } + + qrcode, err := codemapper.NewQrcode(qrcodeTemplate) + + assert.Nil(t, err) + assert.NotNil(t, qrcode) + }) + t.Run("when invalid props is sent, should return an error", func(t *testing.T) { + qrcodeTemplate := map[string]interface{}{ + "props": 1, + "order": 1.0, + "value": "123456789", + } + + qrcode, err := codemapper.NewQrcode(qrcodeTemplate) + + assert.Nil(t, qrcode) + assert.NotNil(t, err) + }) + t.Run("when invalid field is sent, should return an error", func(t *testing.T) { + qrcodeTemplate := map[string]interface{}{ + "invalid_field": 1, + "order": 1.0, + "value": "123456789", + } + + qrcode, err := codemapper.NewQrcode(qrcodeTemplate) + + assert.Nil(t, qrcode) + assert.NotNil(t, err) + }) + t.Run("when source_key and code are not sent, should return an error", func(t *testing.T) { + qrcodeTemplate := map[string]interface{}{} + + qrcode, err := codemapper.NewQrcode(qrcodeTemplate) + + assert.Nil(t, qrcode) + assert.NotNil(t, err) + }) + t.Run("when invalid code is sent, should return an error", func(t *testing.T) { + qrcodeTemplate := map[string]interface{}{ + "order": 1.0, + "value": 123, + } + + qrcode, err := codemapper.NewQrcode(qrcodeTemplate) + + assert.Nil(t, qrcode) + assert.NotNil(t, err) + }) + t.Run("when invalid source_key is sent, should return an error", func(t *testing.T) { + qrcodeTemplate := map[string]interface{}{ + "source_key": 123, + "order": 1.0, + } + + qrcode, err := codemapper.NewQrcode(qrcodeTemplate) + + assert.Nil(t, qrcode) + assert.NotNil(t, err) + }) + t.Run("when code is not sent, should add source key", func(t *testing.T) { + qrcodeTemplate := map[string]interface{}{ + "source_key": "source", + "order": 1.0, + } + + qrcode, err := codemapper.NewQrcode(qrcodeTemplate) + + assert.Nil(t, err) + assert.Equal(t, qrcode.SourceKey, "source") + }) + + t.Run("when source_key is not sent, should add code", func(t *testing.T) { + qrcodeTemplate := map[string]interface{}{ + "order": 1.0, + "value": "code", + } + + qrcode, err := codemapper.NewQrcode(qrcodeTemplate) + + assert.Nil(t, err) + assert.Equal(t, qrcode.Code, "code") + }) +} + +func TestQrCodeGenerate(t *testing.T) { + t.Run("if source key is not found, should return an error", func(t *testing.T) { + content := map[string]interface{}{} + provider := mocks.NewProcessorProvider(t) + + QrCode := codemapper.Qrcode{SourceKey: "code"} + component, err := QrCode.Generate(content, provider) + + assert.Nil(t, component) + assert.NotNil(t, err) + }) + t.Run("if source key content is not valid, should return an error", func(t *testing.T) { + content := map[string]interface{}{ + "code": 1, + } + provider := mocks.NewProcessorProvider(t) + + QrCode := codemapper.Qrcode{SourceKey: "code"} + component, err := QrCode.Generate(content, provider) + + assert.Nil(t, component) + assert.NotNil(t, err) + }) + t.Run("If the QrCode has no props, the props will not be sent", func(t *testing.T) { + content := map[string]interface{}{ + "code": "code", + } + + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateQrCode("code").Return(nil) + + QrCode := codemapper.Qrcode{SourceKey: "code"} + _, err := QrCode.Generate(content, provider) + + assert.Nil(t, err) + provider.AssertNumberOfCalls(t, "CreateQrCode", 1) + }) + t.Run("when valid code is sent, should generate QrCode", func(t *testing.T) { + content := map[string]interface{}{} + + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateQrCode("code").Return(nil) + + QrCode := codemapper.Qrcode{Code: "code"} + _, err := QrCode.Generate(content, provider) + + assert.Nil(t, err) + provider.AssertNumberOfCalls(t, "CreateQrCode", 1) + }) +} diff --git a/pkg/processor/mappers/components/colmapper/col.go b/pkg/processor/mappers/components/colmapper/col.go new file mode 100644 index 00000000..9531cac7 --- /dev/null +++ b/pkg/processor/mappers/components/colmapper/col.go @@ -0,0 +1,151 @@ +package colmapper + +import ( + "fmt" + "strings" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" +) + +type factoryComponent = func(interface{}) (mappers.OrderedComponents, error) + +type Col struct { + Size int + Components []mappers.OrderedComponents + factory mappers.AbstractFactoryMaps + props *propsmapper.Cell +} + +func NewCol(templateCols interface{}, factory mappers.AbstractFactoryMaps) (*Col, error) { + mapCols, ok := templateCols.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure that rows can be converted to map[string] interface{}") + } + + col := &Col{Size: 0, Components: make([]mappers.OrderedComponents, 0), factory: factory} + + if err := col.setProps(&mapCols); err != nil { + return nil, err + } + + if err := col.setSize(&mapCols); err != nil { + return nil, err + } + + if err := col.addComponents(mapCols); err != nil { + return nil, err + } + return col, nil +} + +func (c *Col) addComponents(mapComponents map[string]interface{}) error { + fieldMappers := c.getFieldMappers() + + c.Components = make([]mappers.OrderedComponents, len(mapComponents)) + for templateName, template := range mapComponents { + mapper, err := c.getFieldMapperByTemplateName(templateName, fieldMappers) + if err != nil { + return err + } + component, err := mapper(template) + if err != nil { + return err + } + + if err := c.addComponent(component); err != nil { + return err + } + } + return nil +} + +// addComponent is responsible for validating and adding the component to the template +func (c *Col) addComponent(component mappers.OrderedComponents) error { + order := component.GetOrder() + if order > len(c.Components) { + return fmt.Errorf("component order cannot be greater than %d, this is the number of components in the template", len(c.Components)) + } + if c.Components[order-1] != nil { + return fmt.Errorf("cannot create col template, component order cannot be repeated") + } + + c.Components[order-1] = component + return nil +} + +func (c *Col) setSize(template *map[string]interface{}) error { + defer delete(*template, "size") + templateSize, ok := (*template)["size"] + if ok { + size, ok := templateSize.(float64) + if !ok { + return fmt.Errorf("ensure that size can be converted to int") + } + c.Size = int(size) + } + return nil +} + +// setProps is responsible for creating template col props +func (c *Col) setProps(template *map[string]interface{}) error { + props, ok := (*template)["props"] + if !ok { + return nil + } + defer delete(*template, "props") + + propsRow, err := propsmapper.NewCell(props) + if err != nil { + return err + } + c.props = propsRow + return nil +} + +func (c *Col) getFieldMapperByTemplateName(templateName string, mappers map[string]factoryComponent) (factoryComponent, error) { + for mapperName, mapper := range mappers { + if strings.HasPrefix(templateName, mapperName) { + return mapper, nil + } + } + return nil, fmt.Errorf( + "the field \"%s\" present in the col cannot be mapped to any valid component, ensure the field name starts with a valid component", + templateName) +} + +// getFieldMappers is responsible for defining which methods are responsible for assembling which components. +// To do this, the component name is linked to a function in a Map. +func (c *Col) getFieldMappers() map[string]factoryComponent { + return map[string]factoryComponent{ + "bar_code": c.factory.NewBarcode, + "matrix_code": c.factory.NewMatrixcode, + "qr_code": c.factory.NewQrcode, + "image": c.factory.NewImage, + "line": c.factory.NewLine, + "signature": c.factory.NewSignature, + "text": c.factory.NewText, + } +} + +// Generate is responsible for generating the col component, it will generate all the internal components and add them to the col +// - The content is a map with the properties of the col components +func (c *Col) Generate(content map[string]interface{}, provider processorprovider.ProcessorProvider) ( + []processorprovider.ProviderComponent, error, +) { + components := make([]processorprovider.ProviderComponent, 0, len(c.Components)) + for _, component := range c.Components { + newComponent, err := component.Generate(content, provider) + if err != nil { + return nil, err + } + components = append(components, newComponent...) + } + + col, err := provider.CreateCol(c.Size, c.props, components...) + if err != nil { + return nil, err + } + return []processorprovider.ProviderComponent{col}, nil +} diff --git a/pkg/processor/mappers/components/colmapper/col_test.go b/pkg/processor/mappers/components/colmapper/col_test.go new file mode 100644 index 00000000..56e6c02f --- /dev/null +++ b/pkg/processor/mappers/components/colmapper/col_test.go @@ -0,0 +1,261 @@ +package colmapper_test + +import ( + "errors" + "testing" + + "github.com/johnfercher/maroto/v2/internal/fixture" + "github.com/johnfercher/maroto/v2/mocks" + "github.com/johnfercher/maroto/v2/pkg/components/text" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/codemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/colmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/imagemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/linemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/signaturemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/textmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestNewCol(t *testing.T) { + t.Run("when the template order is greater than the number of components, an error should be returned", func(t *testing.T) { + col := map[string]interface{}{"bar_code": nil} + orderedComponent := mocks.NewOrderedComponents(t) + orderedComponent.EXPECT().GetOrder().Return(2) + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewBarcode", mock.Anything).Return(orderedComponent, nil) + + _, err := colmapper.NewCol(col, factory) + + assert.NotNil(t, err) + }) + + t.Run("when the template order is repeated, an error should be returned", func(t *testing.T) { + col := map[string]interface{}{"bar_code_1": nil, "bar_code_2": nil} + orderedComponent := mocks.NewOrderedComponents(t) + orderedComponent.EXPECT().GetOrder().Return(2) + + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewBarcode", mock.Anything).Return(orderedComponent, nil) + factory.On("NewBarcode", mock.Anything).Return(orderedComponent, nil) + + _, err := colmapper.NewCol(col, factory) + + assert.NotNil(t, err) + }) + + t.Run("when 2 components are submitted, should add the 2 components in the correct order", func(t *testing.T) { + col := map[string]interface{}{"bar_code_1": 1, "bar_code_2": 2} + + orderedComponent1 := mocks.NewOrderedComponents(t) + orderedComponent1.EXPECT().GetOrder().Return(1) + orderedComponent2 := mocks.NewOrderedComponents(t) + orderedComponent2.EXPECT().GetOrder().Return(2) + + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewBarcode", 1).Return(orderedComponent1, nil) + factory.On("NewBarcode", 2).Return(orderedComponent2, nil) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, err) + assert.Equal(t, len(doc.Components), 2) + assert.Equal(t, orderedComponent1, doc.Components[0]) + }) + + t.Run("when a barcode is sent, a barcode is created", func(t *testing.T) { + col := map[string]interface{}{"bar_code": nil} + validBarcode := fixture.Barcode() + + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewBarcode", mock.Anything).Return(validBarcode, nil) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, err) + assert.Len(t, doc.Components, 1) + assert.IsType(t, &codemapper.Barcode{}, doc.Components[0]) + }) + + t.Run("when a matrixcode is sent, a matrixcode is created", func(t *testing.T) { + col := map[string]interface{}{"matrix_code": nil} + validMatrixcode := fixture.Matrixcode() + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewMatrixcode", mock.Anything).Return(validMatrixcode, nil) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, err) + assert.Len(t, doc.Components, 1) + assert.IsType(t, &codemapper.Matrixcode{}, doc.Components[0]) + }) + t.Run("when a qrcode is sent, a qrcode is created", func(t *testing.T) { + col := map[string]interface{}{"qr_code": nil} + validQrcode := fixture.Qrcode() + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewQrcode", mock.Anything).Return(validQrcode, nil) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, err) + assert.Len(t, doc.Components, 1) + assert.IsType(t, &codemapper.Qrcode{}, doc.Components[0]) + }) + t.Run("when a image is sent, a image is created", func(t *testing.T) { + col := map[string]interface{}{"image": nil} + validImage := fixture.Image() + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewImage", mock.Anything).Return(validImage, nil) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, err) + assert.Len(t, doc.Components, 1) + assert.IsType(t, &imagemapper.Image{}, doc.Components[0]) + }) + t.Run("when a line is sent, a line is created", func(t *testing.T) { + col := map[string]interface{}{"line": nil} + validLine := fixture.Line() + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewLine", mock.Anything).Return(validLine, nil) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, err) + assert.Len(t, doc.Components, 1) + assert.IsType(t, &linemapper.Line{}, doc.Components[0]) + }) + t.Run("when a signature is sent, a signature is created", func(t *testing.T) { + col := map[string]interface{}{"signature": nil} + validSignature := fixture.Signature() + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewSignature", mock.Anything).Return(validSignature, nil) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, err) + assert.Len(t, doc.Components, 1) + assert.IsType(t, &signaturemapper.Signature{}, doc.Components[0]) + }) + t.Run("when a text is sent, a text is created", func(t *testing.T) { + col := map[string]interface{}{"text": nil} + validText := fixture.Text() + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewText", mock.Anything).Return(validText, nil) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, err) + assert.Len(t, doc.Components, 1) + assert.IsType(t, &textmapper.Text{}, doc.Components[0]) + }) + t.Run("when no component is sent, no component is added", func(t *testing.T) { + col := map[string]interface{}{} + factory := mocks.NewAbstractFactoryMaps(t) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, err) + assert.Len(t, doc.Components, 0) + }) + t.Run("when an invalid field is sent, an error is returned", func(t *testing.T) { + col := map[string]interface{}{"invalid_field": nil} + factory := mocks.NewAbstractFactoryMaps(t) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, doc) + assert.NotNil(t, err) + }) + t.Run("when an invalid interface is sent, an error is returned", func(t *testing.T) { + var col interface{} = 1 + factory := mocks.NewAbstractFactoryMaps(t) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, doc) + assert.NotNil(t, err) + }) + t.Run("when the component cannot be created, it should return an error", func(t *testing.T) { + col := map[string]interface{}{"text": nil} + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewText", mock.Anything).Return(nil, errors.New("any")) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, doc) + assert.NotNil(t, err) + }) + t.Run("when an invalid size is sent, an error is returned", func(t *testing.T) { + col := map[string]interface{}{"size": "invalid"} + factory := mocks.NewAbstractFactoryMaps(t) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, doc) + assert.NotNil(t, err) + }) + t.Run("when no size is sent, should set size to 0", func(t *testing.T) { + col := map[string]interface{}{} + factory := mocks.NewAbstractFactoryMaps(t) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, err) + assert.Equal(t, doc.Size, 0) + }) + t.Run("when size is sent, should set size", func(t *testing.T) { + col := map[string]interface{}{"size": 6.0} + factory := mocks.NewAbstractFactoryMaps(t) + + doc, err := colmapper.NewCol(col, factory) + + assert.Nil(t, err) + assert.Equal(t, doc.Size, 6) + }) +} + +func TestGenerate(t *testing.T) { + t.Run("when col has no components, it should not send components", func(t *testing.T) { + content := map[string]interface{}{} + col := colmapper.Col{Size: 10, Components: make([]mappers.OrderedComponents, 0)} + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateCol(10, (*propsmapper.Cell)(nil)).Return(nil, nil) + + _, err := col.Generate(content, provider) + + assert.Nil(t, err) + provider.AssertNumberOfCalls(t, "CreateCol", 1) + }) + t.Run("when col has two components, it should add two components", func(t *testing.T) { + content := map[string]interface{}{"text1": "test", "text2": "test"} + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateCol(10, (*propsmapper.Cell)(nil), text.New("test"), text.New("test")).Return(nil, nil) + + component := mocks.NewOrderedComponents(t) + component.EXPECT().Generate(content, provider).Return([]processorprovider.ProviderComponent{text.New("test")}, nil) + col := colmapper.Col{Size: 10, Components: []mappers.OrderedComponents{component, component}} + + _, err := col.Generate(content, provider) + + assert.Nil(t, err) + provider.AssertNumberOfCalls(t, "CreateCol", 1) + component.AssertNumberOfCalls(t, "Generate", 2) + }) + t.Run("when it is not possible to generate the component, an error should be returned", func(t *testing.T) { + content := map[string]interface{}{"text1": "test"} + provider := mocks.NewProcessorProvider(t) + + component := mocks.NewOrderedComponents(t) + component.EXPECT().Generate(content, provider).Return(nil, errors.New("any")) + col := colmapper.Col{Size: 10, Components: []mappers.OrderedComponents{component}} + + _, err := col.Generate(content, provider) + + component.AssertNumberOfCalls(t, "Generate", 1) + assert.NotNil(t, err) + }) +} diff --git a/pkg/processor/mappers/components/imagemapper/image.go b/pkg/processor/mappers/components/imagemapper/image.go new file mode 100644 index 00000000..ee777b9d --- /dev/null +++ b/pkg/processor/mappers/components/imagemapper/image.go @@ -0,0 +1,133 @@ +// Package image implements creation of images from file and bytes. +package imagemapper + +import ( + "fmt" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/order" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" +) + +type Image struct { + Value string + SourceKey string + Props *propsmapper.Rect + Order int +} + +func NewImage(templateImage interface{}) (*Image, error) { + imageMap, ok := templateImage.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure image can be converted to map[string] interface{}") + } + + image := &Image{} + if err := image.addFields(imageMap); err != nil { + return nil, err + } + if image.SourceKey == "" && image.Value == "" { + return nil, fmt.Errorf("no value passed for image. Add the 'source_key' or a value") + } + + return image, nil +} + +// addFields is responsible for adding the barcode fields according to +// the properties informed in the map +func (i *Image) addFields(imageMap map[string]interface{}) error { + order, err := order.SetPageOrder(&imageMap, "image", i.SourceKey) + if err != nil { + return err + } + i.Order = order + fieldMappers := i.getFieldMappers() + + for templateName, template := range imageMap { + mapper, ok := fieldMappers[templateName] + if !ok { + return fmt.Errorf("the field %s present in the image cannot be mapped to any valid field", templateName) + } + err := mapper(template) + if err != nil { + return err + } + } + return nil +} + +// GetOrder is responsible for returning the component's defined order +func (i *Image) GetOrder() int { + return i.Order +} + +// getFieldMappers is responsible for defining which methods are responsible for assembling which components. +// To do this, the component name is linked to a function in a Map. +func (i *Image) getFieldMappers() map[string]func(interface{}) error { + return map[string]func(interface{}) error{ + "source_key": i.setSourceKey, + "props": i.setProps, + "value": i.setPath, + } +} + +func (i *Image) setSourceKey(template interface{}) error { + sourceKey, ok := template.(string) + if !ok { + return fmt.Errorf("source_key cannot be converted to a string") + } + i.SourceKey = sourceKey + return nil +} + +func (i *Image) setPath(template interface{}) error { + path, ok := template.(string) + if !ok { + return fmt.Errorf("path cannot be converted to a string") + } + i.Value = path + return nil +} + +func (i *Image) setProps(template interface{}) error { + props, err := propsmapper.NewRect(template) + if err != nil { + return err + } + i.Props = props + return nil +} + +func (i *Image) getImagePath(content map[string]interface{}) (string, error) { + if i.Value != "" { + return i.Value, nil + } + imageFound, ok := content[i.SourceKey] + if !ok { + return "", fmt.Errorf("image requires a source key named %s, but it was not found", i.SourceKey) + } + imageValid, ok := imageFound.(string) + if !ok { + return "", fmt.Errorf("unable to generate image, invalid path. source key %s", i.SourceKey) + } + return imageValid, nil +} + +func (i *Image) Generate(content map[string]interface{}, provider processorprovider.ProcessorProvider) ( + []processorprovider.ProviderComponent, error, +) { + var err error + i.Value, err = i.getImagePath(content) + if err != nil { + return nil, err + } + + var img processorprovider.ProviderComponent + if i.Props != nil { + img, err = provider.CreateImage(i.Value, i.Props) + } else { + img, err = provider.CreateImage(i.Value) + } + + return []processorprovider.ProviderComponent{img}, err +} diff --git a/pkg/processor/mappers/components/imagemapper/image_test.go b/pkg/processor/mappers/components/imagemapper/image_test.go new file mode 100644 index 00000000..52723655 --- /dev/null +++ b/pkg/processor/mappers/components/imagemapper/image_test.go @@ -0,0 +1,158 @@ +package imagemapper_test + +import ( + "testing" + + "github.com/johnfercher/maroto/v2/mocks" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/imagemapper" + "github.com/stretchr/testify/assert" +) + +func TestGetOrder(t *testing.T) { + t.Run("when getOrder is called, should return defined order", func(t *testing.T) { + templateRows := map[string]interface{}{ + "order": 10.0, + "value": "img", + } + + doc, _ := imagemapper.NewImage(templateRows) + + assert.Equal(t, 10, doc.GetOrder()) + }) +} + +func TestNewImage(t *testing.T) { + t.Run("when invalid image is sent, should return an error", func(t *testing.T) { + imageTemplate := 1 + + image, err := imagemapper.NewImage(imageTemplate) + + assert.Nil(t, image) + assert.NotNil(t, err) + }) + t.Run("when props is not sent, image is created", func(t *testing.T) { + imageTemplate := map[string]interface{}{ + "source_key": "image", + "order": 1.0, + } + + image, err := imagemapper.NewImage(imageTemplate) + + assert.Nil(t, err) + assert.NotNil(t, image) + }) + t.Run("when invalid props is sent, should return an error", func(t *testing.T) { + imageTemplate := map[string]interface{}{ + "props": 1, + "source_key": "name", + "order": 1.0, + } + + image, err := imagemapper.NewImage(imageTemplate) + + assert.Nil(t, image) + assert.NotNil(t, err) + }) + t.Run("when invalid field is sent, should return an error", func(t *testing.T) { + imageTemplate := map[string]interface{}{ + "invalid_field": 1, + "source_key": "name", + "order": 1.0, + } + + image, err := imagemapper.NewImage(imageTemplate) + + assert.Nil(t, image) + assert.NotNil(t, err) + }) + t.Run("when source_key is not sent, should return an error", func(t *testing.T) { + imageTemplate := map[string]interface{}{} + + image, err := imagemapper.NewImage(imageTemplate) + + assert.Nil(t, image) + assert.NotNil(t, err) + }) + t.Run("when invalid source_key is sent, should return an error", func(t *testing.T) { + imageTemplate := map[string]interface{}{ + "source_key": 123, + "order": 1.0, + } + + image, err := imagemapper.NewImage(imageTemplate) + + assert.Nil(t, image) + assert.NotNil(t, err) + }) + t.Run("when source_key and path are not sent, should return an error", func(t *testing.T) { + imageTemplate := map[string]interface{}{} + + image, err := imagemapper.NewImage(imageTemplate) + + assert.Nil(t, image) + assert.NotNil(t, err) + }) + t.Run("when source_key is sent, should add source_key", func(t *testing.T) { + imageTemplate := map[string]interface{}{ + "source_key": "icon", + "order": 1.0, + } + + image, err := imagemapper.NewImage(imageTemplate) + + assert.Nil(t, err) + assert.Equal(t, image.SourceKey, "icon") + }) + t.Run("when props is sent, should add props", func(t *testing.T) { + imageTemplate := map[string]interface{}{ + "source_key": "name", + "order": 1.0, + "props": map[string]interface{}{ + "left": 10.0, + }, + } + + image, err := imagemapper.NewImage(imageTemplate) + + assert.Nil(t, err) + assert.Equal(t, 10.0, image.Props.Left) + }) +} + +func TestImageGenerate(t *testing.T) { + t.Run("if image is not found, should return an error", func(t *testing.T) { + content := map[string]interface{}{} + provider := mocks.NewProcessorProvider(t) + + image := imagemapper.Image{SourceKey: "code"} + component, err := image.Generate(content, provider) + + assert.Nil(t, component) + assert.NotNil(t, err) + }) + t.Run("if image content is not valid, should return an error", func(t *testing.T) { + content := map[string]interface{}{ + "code": 1, + } + provider := mocks.NewProcessorProvider(t) + + image := imagemapper.Image{SourceKey: "code"} + component, err := image.Generate(content, provider) + + assert.Nil(t, component) + assert.NotNil(t, err) + }) + t.Run("If the image has no props, the props will not be sent", func(t *testing.T) { + content := map[string]interface{}{ + "Path": "path.png", + } + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateImage("path.png").Return(nil, nil) + + image := imagemapper.Image{SourceKey: "Path"} + _, err := image.Generate(content, provider) + + assert.Nil(t, err) + provider.AssertNumberOfCalls(t, "CreateImage", 1) + }) +} diff --git a/pkg/processor/mappers/components/linemapper/line.go b/pkg/processor/mappers/components/linemapper/line.go new file mode 100644 index 00000000..3cbb213a --- /dev/null +++ b/pkg/processor/mappers/components/linemapper/line.go @@ -0,0 +1,82 @@ +// Package line implements creation of lines. +package linemapper + +import ( + "fmt" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/order" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" +) + +type Line struct { + Props *propsmapper.Line + Order int +} + +func NewLine(code interface{}) (*Line, error) { + lineMapper, ok := code.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure line can be converted to map[string] interface{}") + } + line := &Line{} + + if err := line.addFields(lineMapper); err != nil { + return nil, err + } + return line, nil +} + +// addFields is responsible for adding the barcode fields according to +// the properties informed in the map +func (l *Line) addFields(lineMapper map[string]interface{}) error { + order, err := order.SetPageOrder(&lineMapper, "line", "") + if err != nil { + return err + } + l.Order = order + fieldMappers := l.getFieldMappers() + + for templateName, template := range lineMapper { + mapper, ok := fieldMappers[templateName] + if !ok { + return fmt.Errorf("the field %s present in the line cannot be mapped to any valid field", templateName) + } + err := mapper(template) + if err != nil { + return err + } + } + return nil +} + +// GetOrder is responsible for returning the component's defined order +func (l *Line) GetOrder() int { + return l.Order +} + +// getFieldMappers is responsible for defining which methods are responsible for assembling which components. +// To do this, the component name is linked to a function in a Map. +func (l *Line) getFieldMappers() map[string]func(interface{}) error { + return map[string]func(interface{}) error{ + "props": l.setProps, + } +} + +func (l *Line) setProps(templateProps interface{}) error { + propsLine, err := propsmapper.NewLine(templateProps) + if err != nil { + return err + } + l.Props = propsLine + return nil +} + +func (l *Line) Generate(content map[string]interface{}, provider processorprovider.ProcessorProvider) ( + []processorprovider.ProviderComponent, error, +) { + if l.Props != nil { + return []processorprovider.ProviderComponent{provider.CreateLine(l.Props)}, nil + } + return []processorprovider.ProviderComponent{provider.CreateLine()}, nil +} diff --git a/pkg/processor/mappers/components/linemapper/line_test.go b/pkg/processor/mappers/components/linemapper/line_test.go new file mode 100644 index 00000000..5ed43f2c --- /dev/null +++ b/pkg/processor/mappers/components/linemapper/line_test.go @@ -0,0 +1,65 @@ +// Package line implements creation of lines. +package linemapper_test + +import ( + "testing" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/linemapper" + "github.com/stretchr/testify/assert" +) + +func TestQrcodeGetOrder(t *testing.T) { + t.Run("when getOrder is called, should return defined order", func(t *testing.T) { + templateRows := map[string]interface{}{ + "order": 10.0, + } + + doc, _ := linemapper.NewLine(templateRows) + + assert.Equal(t, 10, doc.GetOrder()) + }) +} + +func TestNewLine(t *testing.T) { + t.Run("when invalid line is sent, should return an error", func(t *testing.T) { + lineTemplate := 1 + + line, err := linemapper.NewLine(lineTemplate) + + assert.Nil(t, line) + assert.NotNil(t, err) + }) + t.Run("when props is not sent, line is created", func(t *testing.T) { + lineTemplate := map[string]interface{}{ + "order": 1.0, + } + + line, err := linemapper.NewLine(lineTemplate) + + assert.Nil(t, err) + assert.NotNil(t, line) + }) + t.Run("when invalid props is sent, should return an error", func(t *testing.T) { + lineTemplate := map[string]interface{}{ + "props": 1, + "order": 1.0, + } + + line, err := linemapper.NewLine(lineTemplate) + + assert.Nil(t, line) + assert.NotNil(t, err) + }) + t.Run("when invalid field is sent, should return an error", func(t *testing.T) { + lineTemplate := map[string]interface{}{ + "invalid_field": 1, + "code": "123456789", + "order": 1.0, + } + + line, err := linemapper.NewLine(lineTemplate) + + assert.Nil(t, line) + assert.NotNil(t, err) + }) +} diff --git a/pkg/processor/mappers/components/listmapper/list.go b/pkg/processor/mappers/components/listmapper/list.go new file mode 100644 index 00000000..e3e211ca --- /dev/null +++ b/pkg/processor/mappers/components/listmapper/list.go @@ -0,0 +1,140 @@ +// listmapper is the package responsible for mapping row settings +package listmapper + +import ( + "fmt" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" +) + +// The List component is responsible for adding a list behavior to a component. +// It will repeat a component for each content sent in the generate method +type List struct { + SourceKey string + Templates []mappers.OrderedComponents + order int +} + +func NewList(list interface{}, sourceKey string, generate mappers.GenerateComponent) (*List, error) { + listMapper, ok := list.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure list can be converted to map[string] interface{}") + } + + newList := List{SourceKey: sourceKey} + if err := newList.setListOrder(&listMapper, sourceKey); err != nil { + return nil, err + } + + if err := newList.setComponents(listMapper, generate); err != nil { + return nil, err + } + return &newList, nil +} + +// setComponents is responsible for generating the list component. Components will be generated through the generate method +func (l *List) setComponents(listMapper map[string]interface{}, generate mappers.GenerateComponent) error { + l.Templates = make([]mappers.OrderedComponents, len(listMapper)) + + for templateName, template := range listMapper { + component, err := generate(template, templateName) + if err != nil { + return err + } + if err := l.addComponent(component); err != nil { + return err + } + } + return nil +} + +// addComponent is responsible for validating and adding the component to the template +func (l *List) addComponent(component mappers.OrderedComponents) error { + order := component.GetOrder() + if component.GetOrder() > len(l.Templates) { + return fmt.Errorf("component order cannot be greater than %d, this is the number of components in the template", len(l.Templates)) + } + if l.Templates[order-1] != nil { + return fmt.Errorf("cannot create list template, component order cannot be repeated") + } + + l.Templates[order-1] = component + return nil +} + +func (l *List) GetOrder() int { + return l.order +} + +// formatListContent is responsible for converting content into []map[string]interface{} +func (l *List) formatListContent(content interface{}) ([]map[string]interface{}, error) { + listContent, ok := content.([]interface{}) + if !ok { + return nil, fmt.Errorf("ensure that the contents of the list \"%s\" can be converted to []map[string]interface{}", l.SourceKey) + } + + contentMaps := make([]map[string]interface{}, 0, len(listContent)) + for _, content := range listContent { + contentMap, ok := content.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure that the contents of the list \"%s\" can be converted to []map[string]interface{}", l.SourceKey) + } + contentMaps = append(contentMaps, contentMap) + } + return contentMaps, nil +} + +func (l *List) getListContent(content map[string]interface{}) ([]map[string]interface{}, error) { + listContent, ok := content[l.SourceKey] + if !ok { + return nil, fmt.Errorf("the list needs the source key \"%s\", but it was not found", l.SourceKey) + } + + return l.formatListContent(listContent) +} + +func (l *List) generateTemplates(content map[string]interface{}, + provider processorprovider.ProcessorProvider, +) []processorprovider.ProviderComponent { + components := make([]processorprovider.ProviderComponent, 0, len(l.Templates)) + for _, template := range l.Templates { + if component, err := template.Generate(content, provider); err == nil { + components = append(components, component...) + } + } + return components +} + +func (l *List) Generate(content map[string]interface{}, provider processorprovider.ProcessorProvider) ( + []processorprovider.ProviderComponent, error, +) { + listContent, err := l.getListContent(content) + if err != nil { + return nil, err + } + newComponents := make([]processorprovider.ProviderComponent, 0, len(l.Templates)*len(listContent)) + + for _, content := range listContent { + components := l.generateTemplates(content, provider) + newComponents = append(newComponents, components...) + } + + return newComponents, nil +} + +// setListOrder is responsible for validating the component order and adding the order to the list +func (l *List) setListOrder(template *map[string]interface{}, sourceKey string) error { + order, ok := (*template)["order"] + if !ok { + return fmt.Errorf("could not find field order on list \"%s\"", sourceKey) + } + validOrder, ok := order.(float64) + if !ok || validOrder < 1 { + return fmt.Errorf("the order field passed on list \"%s\" is not valid", sourceKey) + } + + delete(*template, "order") + l.order = int(validOrder) + return nil +} diff --git a/pkg/processor/mappers/components/listmapper/list_test.go b/pkg/processor/mappers/components/listmapper/list_test.go new file mode 100644 index 00000000..1c764bb3 --- /dev/null +++ b/pkg/processor/mappers/components/listmapper/list_test.go @@ -0,0 +1,194 @@ +package listmapper_test + +import ( + "errors" + "testing" + + "github.com/johnfercher/maroto/v2/mocks" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/listmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestGetOrder(t *testing.T) { + t.Run("when getOrder is called, should return defined order", func(t *testing.T) { + templateRows := map[string]interface{}{ + "order": 10.0, + } + factory := mocks.NewAbstractFactoryMaps(t) + + doc, _ := listmapper.NewList(templateRows, "test", factory.NewRow) + + assert.Equal(t, 10, doc.GetOrder()) + }) +} + +func TestNewList(t *testing.T) { + t.Run("when invalid interface is sent, it should return an error", func(t *testing.T) { + var invalidInterface interface{} = 1 + factory := mocks.NewAbstractFactoryMaps(t) + + doc, err := listmapper.NewList(invalidInterface, "test", factory.NewPage) + + assert.Nil(t, doc) + assert.NotNil(t, err) + }) + + t.Run("when the component order is greater than the number of components, an error should be returned", func(t *testing.T) { + templateList := map[string]interface{}{ + "page_template_1": nil, + "order": 1.0, + } + + orderedComponent := mocks.NewOrderedComponents(t) + orderedComponent.EXPECT().GetOrder().Return(2) + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewPage", mock.Anything, "page_template_1").Return(orderedComponent, nil) + + _, err := listmapper.NewList(templateList, "test", factory.NewPage) + + assert.NotNil(t, err) + }) + + t.Run("when the template order is repeated, an error should be returned", func(t *testing.T) { + templateList := map[string]interface{}{ + "page_template_1": nil, + "page_template_2": nil, + "order": 1.0, + } + + orderedComponent := mocks.NewOrderedComponents(t) + orderedComponent.EXPECT().GetOrder().Return(2) + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewPage", mock.Anything, "page_template_1").Return(orderedComponent, nil) + factory.On("NewPage", mock.Anything, "page_template_2").Return(orderedComponent, nil) + + _, err := listmapper.NewList(templateList, "test", factory.NewPage) + + assert.NotNil(t, err) + }) + + t.Run("when 2 pages are submitted, should add the 2 pages in the correct order", func(t *testing.T) { + templatePages := map[string]interface{}{ + "page_template_2": nil, + "page_template_1": nil, + "order": 1.0, + } + orderedComponent1 := mocks.NewOrderedComponents(t) + orderedComponent1.EXPECT().GetOrder().Return(1) + orderedComponent2 := mocks.NewOrderedComponents(t) + orderedComponent2.EXPECT().GetOrder().Return(2) + + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewPage", mock.Anything, "page_template_1").Return(orderedComponent1, nil) + factory.On("NewPage", mock.Anything, "page_template_2").Return(orderedComponent2, nil) + + doc, err := listmapper.NewList(templatePages, "test", factory.NewPage) + + assert.Nil(t, err) + assert.Equal(t, len(doc.Templates), 2) + assert.Equal(t, orderedComponent1, doc.Templates[0]) + }) + + t.Run("when component not can generate, it should return an error", func(t *testing.T) { + templatePages := map[string]interface{}{ + "page_template_1": nil, + "page_template_2": nil, + "order": 1.0, + } + + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewPage", mock.Anything, "page_template_1").Return(nil, errors.New("")) + doc, err := listmapper.NewList(templatePages, "test", factory.NewPage) + + assert.Nil(t, doc) + assert.NotNil(t, err) + }) + + t.Run("when the order field is not sent, should return an error", func(t *testing.T) { + templateRows := map[string]interface{}{ + "row_template_1": nil, + } + factory := mocks.NewAbstractFactoryMaps(t) + + _, err := listmapper.NewList(templateRows, "test", factory.NewRow) + + assert.NotNil(t, err) + }) + + t.Run("when the order field is less than 1, should return an error", func(t *testing.T) { + templateRows := map[string]interface{}{ + "row_template_1": nil, + "order": 0, + } + factory := mocks.NewAbstractFactoryMaps(t) + + _, err := listmapper.NewList(templateRows, "test", factory.NewRow) + + assert.NotNil(t, err) + }) + + t.Run("when 2-components are sent, it should add 2 components in list", func(t *testing.T) { + templatePages := map[string]interface{}{ + "page_template_1": nil, + "page_template_2": nil, + "order": 1.0, + } + orderedComponent1 := mocks.NewOrderedComponents(t) + orderedComponent1.EXPECT().GetOrder().Return(1) + orderedComponent2 := mocks.NewOrderedComponents(t) + orderedComponent2.EXPECT().GetOrder().Return(2) + + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewPage", mock.Anything, "page_template_1").Return(orderedComponent1, nil) + factory.On("NewPage", mock.Anything, "page_template_2").Return(orderedComponent2, nil) + + doc, err := listmapper.NewList(templatePages, "test", factory.NewPage) + + assert.Nil(t, err) + assert.Equal(t, len(doc.Templates), 2) + }) +} + +func TestGenerate(t *testing.T) { + t.Run("when source_key is not found, should return an error", func(t *testing.T) { + provider := mocks.NewProcessorProvider(t) + content := map[string]interface{}{} + list := listmapper.List{SourceKey: "list", Templates: make([]mappers.OrderedComponents, 0)} + + components, err := list.Generate(content, provider) + + assert.Nil(t, components) + assert.NotNil(t, err) + }) + t.Run("when invalid content is sent, should return an error", func(t *testing.T) { + provider := mocks.NewProcessorProvider(t) + content := map[string]interface{}{"list": 1} + list := listmapper.List{SourceKey: "list", Templates: make([]mappers.OrderedComponents, 0)} + + components, err := list.Generate(content, provider) + + assert.Nil(t, components) + assert.NotNil(t, err) + }) + + t.Run("when 2 templates are added, it should generate 4 components", func(t *testing.T) { + content1 := map[string]interface{}{"row_1": nil, "row_2": nil} + content2 := map[string]interface{}{"row_1": nil, "row_2": nil} + listContent := map[string]interface{}{"list": []interface{}{content1, content2}} + provider := mocks.NewProcessorProvider(t) + providerComponent := mocks.NewProviderComponent(t) + component := mocks.NewOrderedComponents(t) + component.EXPECT().Generate(mock.Anything, provider).Return([]processorprovider.ProviderComponent{providerComponent}, nil) + + list := listmapper.List{SourceKey: "list", Templates: []mappers.OrderedComponents{component, component}} + components, err := list.Generate(listContent, provider) + + assert.NotNil(t, components) + assert.Nil(t, err) + component.AssertNumberOfCalls(t, "Generate", 4) + assert.Len(t, components, 4) + }) +} diff --git a/pkg/processor/mappers/components/order/componentorganizer.go b/pkg/processor/mappers/components/order/componentorganizer.go new file mode 100644 index 00000000..3a8a3553 --- /dev/null +++ b/pkg/processor/mappers/components/order/componentorganizer.go @@ -0,0 +1,23 @@ +// ordering package is a group of functions associated with component ordering, +// This package seeks to avoid code duplication between ordered components +package order + +import ( + "fmt" +) + +// SetPageOrder is responsible for validating the component order and adding the order to the page +func SetPageOrder(template *map[string]interface{}, resourceName, sourceKey string) (int, error) { + defer delete(*template, "order") + + order, ok := (*template)["order"] + if !ok { + return 0, fmt.Errorf("could not find field order on %s \"%s\"", resourceName, sourceKey) + } + validOrder, ok := order.(float64) + if !ok || validOrder < 1 { + return 0, fmt.Errorf("the order field passed on %s \"%s\" is not valid", resourceName, sourceKey) + } + + return int(validOrder), nil +} diff --git a/pkg/processor/mappers/components/order/componentorganizer_test.go b/pkg/processor/mappers/components/order/componentorganizer_test.go new file mode 100644 index 00000000..fb132ae9 --- /dev/null +++ b/pkg/processor/mappers/components/order/componentorganizer_test.go @@ -0,0 +1,42 @@ +package order_test + +import ( + "testing" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/order" + "github.com/stretchr/testify/assert" +) + +func TestN(t *testing.T) { + t.Run("when the order field is not sent, should return an error", func(t *testing.T) { + template := map[string]interface{}{ + "template_1": nil, + } + + _, err := order.SetPageOrder(&template, "resource_name", "resource_key") + + assert.NotNil(t, err) + }) + t.Run("when the order field is less than 1, should return an error", func(t *testing.T) { + template := map[string]interface{}{ + "row_template_1": nil, + "order": 0.0, + } + + _, err := order.SetPageOrder(&template, "resource_name", "resource_key") + + assert.NotNil(t, err) + }) + t.Run("when the order field found, should remove order field", func(t *testing.T) { + template := map[string]interface{}{ + "row_template_1": nil, + "order": 1.0, + } + + _, err := order.SetPageOrder(&template, "resource_name", "resource_key") + _, ok := template["order"] + + assert.Nil(t, err) + assert.False(t, ok) + }) +} diff --git a/pkg/processor/mappers/components/pagemapper/page.go b/pkg/processor/mappers/components/pagemapper/page.go new file mode 100644 index 00000000..8338184f --- /dev/null +++ b/pkg/processor/mappers/components/pagemapper/page.go @@ -0,0 +1,137 @@ +// pagemapper is the package responsible for mapping page settings +package pagemapper + +import ( + "fmt" + "strings" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" +) + +type Page struct { + SourceKey string + Rows []mappers.OrderedComponents + Factory mappers.AbstractFactoryMaps + order int +} + +// NewPage is responsible for create an template page +func NewPage(templatePage interface{}, sourceKey string, factory mappers.AbstractFactoryMaps) (*Page, error) { + newPage := &Page{ + SourceKey: sourceKey, + Factory: factory, + } + if err := newPage.setRows(templatePage); err != nil { + return nil, err + } + + return newPage, nil +} + +// setPages is responsible for factory the pages. +// pages can be a list of pages or just one page +func (p *Page) setRows(rowsDoc interface{}) error { + templateRows, ok := rowsDoc.(map[string]interface{}) + if !ok { + return fmt.Errorf("could not parse template, ensure rows can be converted to map[string] interface{}") + } + err := p.setPageOrder(&templateRows) + if err != nil { + return err + } + + p.Rows = make([]mappers.OrderedComponents, len(templateRows)) + for templateName, template := range templateRows { + var row mappers.OrderedComponents + + if strings.HasPrefix(templateName, "list") { + row, err = p.Factory.NewList(template, templateName, p.Factory.NewRow) + } else { + row, err = p.Factory.NewRow(template, templateName) + } + + if err != nil { + return err + } + + if err := p.addComponent(row); err != nil { + return err + } + } + return nil +} + +// addPage is responsible for validating and adding the page to the template +func (p *Page) addComponent(row mappers.OrderedComponents) error { + order := row.GetOrder() + if order > len(p.Rows) { + return fmt.Errorf("component order cannot be greater than %d, this is the number of components in the template", len(p.Rows)) + } + if p.Rows[order-1] != nil { + return fmt.Errorf("cannot create page template, component order cannot be repeated") + } + + p.Rows[order-1] = row + return nil +} + +// GetOrder is responsible for returning the component's defined order +func (p *Page) GetOrder() int { + return p.order +} + +// setPageOrder is responsible for validating the component order and adding the order to the page +func (p *Page) setPageOrder(template *map[string]interface{}) error { + order, ok := (*template)["order"] + if !ok { + return fmt.Errorf("could not find field order on page \"%s\"", p.SourceKey) + } + validOrder, ok := order.(float64) + if !ok || validOrder < 1 { + return fmt.Errorf("the order field passed on page \"%s\" is not valid", p.SourceKey) + } + + p.order = int(validOrder) + delete(*template, "order") + return nil +} + +func (p *Page) getPageContent(content map[string]interface{}) (map[string]interface{}, error) { + pageContent, ok := content[p.SourceKey] + if !ok { + return map[string]interface{}{}, nil + } + if mapPage, ok := pageContent.(map[string]interface{}); ok { + return mapPage, nil + } + return nil, fmt.Errorf( + "could not parse template, ensure that the contents of the page \"%s\" can be converted to map[string]interface{}", + p.SourceKey, + ) +} + +// Generate is responsible for computing the page component with shipping data +func (p *Page) Generate(content map[string]interface{}, provider processorprovider.ProcessorProvider) ( + []processorprovider.ProviderComponent, error, +) { + pageContent, err := p.getPageContent(content) + if err != nil { + return nil, err + } + + rows := make([]processorprovider.ProviderComponent, 0, len(p.Rows)) + for _, row := range p.Rows { + newRow, err := row.Generate(pageContent, provider) + if err != nil { + return nil, err + } + rows = append(rows, newRow...) + } + + page, err := provider.CreatePage(rows...) + if err != nil { + return nil, err + } + return []processorprovider.ProviderComponent{page}, nil +} diff --git a/pkg/processor/mappers/components/pagemapper/page_test.go b/pkg/processor/mappers/components/pagemapper/page_test.go new file mode 100644 index 00000000..6bbb7f78 --- /dev/null +++ b/pkg/processor/mappers/components/pagemapper/page_test.go @@ -0,0 +1,208 @@ +package pagemapper_test + +import ( + "fmt" + "testing" + + "github.com/johnfercher/maroto/v2/mocks" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/pagemapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestGetOrder(t *testing.T) { + t.Run("when getOrder is called, should return defined order", func(t *testing.T) { + templateRows := map[string]interface{}{ + "order": 10.0, + } + doc, _ := pagemapper.NewPage(templateRows, "test", mocks.NewAbstractFactoryMaps(t)) + + assert.Equal(t, 10, doc.GetOrder()) + }) +} + +func TestNewPage(t *testing.T) { + t.Run("when the component order is greater than the number of components, an error should be returned", func(t *testing.T) { + templateRows := map[string]interface{}{ + "row_template_1": nil, + "order": 1.0, + } + + orderedComponent := mocks.NewOrderedComponents(t) + orderedComponent.EXPECT().GetOrder().Return(2) + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewRow", mock.Anything, "row_template_1").Return(orderedComponent, nil) + + _, err := pagemapper.NewPage(templateRows, "test", factory) + + assert.NotNil(t, err) + }) + + t.Run("when the template order is repeated, an error should be returned", func(t *testing.T) { + templateRows := map[string]interface{}{ + "row_template_1": nil, + "row_template_2": nil, + "order": 1.0, + } + + orderedComponent := mocks.NewOrderedComponents(t) + orderedComponent.EXPECT().GetOrder().Return(1) + + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewRow", mock.Anything, "row_template_1").Return(orderedComponent, nil) + factory.On("NewRow", mock.Anything, "row_template_2").Return(orderedComponent, nil) + + _, err := pagemapper.NewPage(templateRows, "test", factory) + + assert.NotNil(t, err) + }) + + t.Run("when 2 rows are submitted, should add the 2 rows in the correct order", func(t *testing.T) { + templateRows := map[string]interface{}{ + "row_template_2": nil, + "row_template_1": nil, + "order": 1.0, + } + + orderedComponent1 := mocks.NewOrderedComponents(t) + orderedComponent1.EXPECT().GetOrder().Return(1) + orderedComponent2 := mocks.NewOrderedComponents(t) + orderedComponent2.EXPECT().GetOrder().Return(2) + + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewRow", mock.Anything, "row_template_1").Return(orderedComponent1, nil) + factory.On("NewRow", mock.Anything, "row_template_2").Return(orderedComponent2, nil) + + doc, err := pagemapper.NewPage(templateRows, "test", factory) + + assert.Nil(t, err) + assert.Equal(t, len(doc.Rows), 2) + assert.Equal(t, orderedComponent1, doc.Rows[0]) + }) + + t.Run("When an invalid field is submitted, should return an error", func(t *testing.T) { + var invalidInterface interface{} = 1 + factory := mocks.NewAbstractFactoryMaps(t) + + doc, err := pagemapper.NewPage(invalidInterface, "test", factory) + + assert.Nil(t, doc) + assert.NotNil(t, err) + }) + + t.Run("When 2 rows are sent, should set the 2 rows", func(t *testing.T) { + templateRows := map[string]interface{}{ + "row_template_1": nil, + "row_template_2": nil, + "order": 1.0, + } + + orderedComponent1 := mocks.NewOrderedComponents(t) + orderedComponent1.EXPECT().GetOrder().Return(1) + orderedComponent2 := mocks.NewOrderedComponents(t) + orderedComponent2.EXPECT().GetOrder().Return(2) + + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewRow", mock.Anything, "row_template_1").Return(orderedComponent1, nil) + factory.On("NewRow", mock.Anything, "row_template_2").Return(orderedComponent2, nil) + + doc, err := pagemapper.NewPage(templateRows, "test", factory) + + assert.Nil(t, err) + assert.Equal(t, 2, len(doc.Rows)) + }) + + t.Run("when 1 list is sent, it should add 1 list to the document", func(t *testing.T) { + templateRows := map[string]interface{}{ + "list_rows_1": nil, + "order": 1.0, + } + + orderedComponent1 := mocks.NewOrderedComponents(t) + orderedComponent1.EXPECT().GetOrder().Return(1) + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewList", mock.Anything, "list_rows_1", mock.Anything).Return(orderedComponent1, nil) + + doc, err := pagemapper.NewPage(templateRows, "test", factory) + + assert.Nil(t, err) + assert.Equal(t, len(doc.Rows), 1) + }) + + t.Run("when the order field is not sent, should return an error", func(t *testing.T) { + templateRows := map[string]interface{}{ + "row_template_1": nil, + } + factory := mocks.NewAbstractFactoryMaps(t) + + _, err := pagemapper.NewPage(templateRows, "test", factory) + + assert.NotNil(t, err) + }) + + t.Run("when the order field is less than 1, should return an error", func(t *testing.T) { + templateRows := map[string]interface{}{ + "row_template_1": nil, + "order": 0, + } + factory := mocks.NewAbstractFactoryMaps(t) + + _, err := pagemapper.NewPage(templateRows, "test", factory) + + assert.NotNil(t, err) + }) +} + +func TestGenerate(t *testing.T) { + t.Run("when content no has source_key, should return an error", func(t *testing.T) { + content := map[string]interface{}{} + factory := mocks.NewAbstractFactoryMaps(t) + providercomponent := []processorprovider.ProviderComponent{mocks.NewProviderComponent(t)} + provider := mocks.NewProcessorProvider(t) + component := mocks.NewOrderedComponents(t) + component.EXPECT().Generate(content, provider).Return(providercomponent, nil) + provider.EXPECT().CreatePage(providercomponent[0]).Return(nil, nil) + + page := pagemapper.Page{Rows: []mappers.OrderedComponents{component}, Factory: factory, SourceKey: "test"} + newPage, err := page.Generate(content, provider) + + assert.Nil(t, err) + assert.NotNil(t, newPage) + }) + t.Run("when page no has rows, it should no sent rows", func(t *testing.T) { + content := map[string]interface{}{"content": map[string]interface{}{"row_1": "any"}} + factory := mocks.NewAbstractFactoryMaps(t) + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreatePage().Return(nil, nil) + + page := pagemapper.Page{Rows: make([]mappers.OrderedComponents, 0), Factory: factory, SourceKey: "content"} + _, err := page.Generate(content, provider) + + assert.Nil(t, err) + }) + t.Run("when is not possible generate components, should return an error", func(t *testing.T) { + content := map[string]interface{}{"content": map[string]interface{}{"text": "value"}} + factory := mocks.NewAbstractFactoryMaps(t) + provider := mocks.NewProcessorProvider(t) + component := mocks.NewOrderedComponents(t) + component.EXPECT().Generate(mock.Anything, provider).Return(nil, fmt.Errorf("any")) + + page := pagemapper.Page{Rows: []mappers.OrderedComponents{component}, Factory: factory, SourceKey: "content"} + _, err := page.Generate(content, provider) + + assert.NotNil(t, err) + }) + t.Run("when is not possible generate page, should return an error", func(t *testing.T) { + content := map[string]interface{}{"content": map[string]interface{}{"text": "value"}} + factory := mocks.NewAbstractFactoryMaps(t) + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreatePage().Return(nil, fmt.Errorf("any")) + + page := pagemapper.Page{Rows: make([]mappers.OrderedComponents, 0), Factory: factory, SourceKey: "content"} + _, err := page.Generate(content, provider) + + assert.NotNil(t, err) + }) +} diff --git a/pkg/processor/mappers/components/rowmapper/row.go b/pkg/processor/mappers/components/rowmapper/row.go new file mode 100644 index 00000000..41c9000a --- /dev/null +++ b/pkg/processor/mappers/components/rowmapper/row.go @@ -0,0 +1,174 @@ +// rowmapper is the package responsible for mapping row settings +package rowmapper + +import ( + "fmt" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" +) + +type Row struct { + Height float64 + Props *propsmapper.Cell + Cols []mappers.Componentmapper + Factory mappers.AbstractFactoryMaps + SourceKey string + order int +} + +// NewRow is responsible for creating a row template +func NewRow(templateRows interface{}, sourceKey string, factory mappers.AbstractFactoryMaps) (*Row, error) { + mapRows, ok := templateRows.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("could not parse template, ensure that rows can be converted to map[string] interface{}") + } + row := &Row{ + Height: 0, + Cols: make([]mappers.Componentmapper, 0), + Factory: factory, + SourceKey: sourceKey, + } + + if err := row.setComponentOrder(&mapRows); err != nil { + return nil, err + } + + err := row.addComponents(mapRows) + if err != nil { + return nil, err + } + return row, nil +} + +// GetOrder is responsible for returning the component's defined order +func (r *Row) GetOrder() int { + return r.order +} + +// setPageOrder is responsible for validating the component order and adding the order to the page +func (r *Row) setComponentOrder(template *map[string]interface{}) error { + order, ok := (*template)["order"] + if !ok { + return fmt.Errorf("could not find field order on page \"%s\"", r.SourceKey) + } + validOrder, ok := order.(float64) + if !ok { + return fmt.Errorf("the order field passed on row \"%s\" is not valid", r.SourceKey) + } + if validOrder < 1 { + return fmt.Errorf("the order field in \"%s\" must be greater than 0", r.SourceKey) + } + + r.order = int(validOrder) + delete(*template, "order") + return nil +} + +// addComponents is responsible for adding the row components according to +// the properties informed in the map +func (r *Row) addComponents(mapRows map[string]interface{}) error { + fieldMappers := r.getFieldMappers() + + for templateName, template := range mapRows { + mapper, ok := fieldMappers[templateName] + if !ok { + return fmt.Errorf("could not parse template, the field %s present in the row cannot be mapped to any valid component", templateName) + } + err := mapper(template) + if err != nil { + return err + } + } + return nil +} + +// setHeight is responsible for creating template row height +func (r *Row) setHeight(template interface{}) error { + height, ok := template.(float64) + if !ok { + return fmt.Errorf("could not parse \"%s\" template, ensure that height can be converted to float64", r.SourceKey) + } + r.Height = height + return nil +} + +// setCols is responsible for creating template row cols +func (r *Row) setCols(template interface{}) error { + cols, ok := template.([]interface{}) + if !ok { + return fmt.Errorf("could not parse \"%s\" template, ensure that cols can be converted to []interface{}", r.SourceKey) + } + r.Cols = make([]mappers.Componentmapper, len(cols)) + + for i, col := range cols { + newCol, err := r.Factory.NewCol(col) + if err != nil { + return err + } + r.Cols[i] = newCol + } + + return nil +} + +// setProps is responsible for creating template row props +func (r *Row) setProps(template interface{}) error { + propsRow, err := propsmapper.NewCell(template) + if err != nil { + return err + } + r.Props = propsRow + return nil +} + +// getFieldMappers is responsible for defining which methods are responsible for assembling which components. +// To do this, the component name is linked to a function in a Map. +func (r *Row) getFieldMappers() map[string]func(interface{}) error { + return map[string]func(interface{}) error{ + "height": r.setHeight, + "cols": r.setCols, + "props": r.setProps, + } +} + +// getRowContent is responsible for getting content data according to sourceKey +func (r *Row) getRowContent(content map[string]interface{}) (map[string]interface{}, error) { + rowContent, ok := content[r.SourceKey] + if !ok { + return map[string]interface{}{}, nil + } + if mapRow, ok := rowContent.(map[string]interface{}); ok { + return mapRow, nil + } + return nil, fmt.Errorf( + "could not parse template, ensure that the contents of the row \"%s\" can be converted to map[string]interface{}", + r.SourceKey, + ) +} + +// Generate is responsible for computer template and generate line component +func (r *Row) Generate(content map[string]interface{}, provider processorprovider.ProcessorProvider) ( + []processorprovider.ProviderComponent, error, +) { + rowContent, err := r.getRowContent(content) + if err != nil { + return nil, err + } + + cols := make([]processorprovider.ProviderComponent, 0, len(r.Cols)) + for _, col := range r.Cols { + newCol, err := col.Generate(rowContent, provider) + if err != nil { + return nil, err + } + cols = append(cols, newCol...) + } + + row, err := provider.CreateRow(r.Height, r.Props, cols...) + if err != nil { + return nil, err + } + return []processorprovider.ProviderComponent{row}, nil +} diff --git a/pkg/processor/mappers/components/rowmapper/row_test.go b/pkg/processor/mappers/components/rowmapper/row_test.go new file mode 100644 index 00000000..02c728c3 --- /dev/null +++ b/pkg/processor/mappers/components/rowmapper/row_test.go @@ -0,0 +1,178 @@ +package rowmapper_test + +import ( + "fmt" + "testing" + + "github.com/johnfercher/maroto/v2/mocks" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/rowmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestGetOrder(t *testing.T) { + t.Run("when getOrder is called, should return defined order", func(t *testing.T) { + templateRows := map[string]interface{}{ + "order": 10.0, + } + factory := mocks.NewAbstractFactoryMaps(t) + + doc, _ := rowmapper.NewRow(templateRows, "test", factory) + + assert.Equal(t, 10, doc.GetOrder()) + }) +} + +func TestNewRow(t *testing.T) { + t.Run("when invalid interface is sent, should return an error", func(t *testing.T) { + factory := mocks.NewAbstractFactoryMaps(t) + var templateRow interface{} = 1 + + doc, err := rowmapper.NewRow(templateRow, "", factory) + + assert.Nil(t, doc) + assert.NotNil(t, err) + }) + t.Run("when row height is not sent, should set height to 0", func(t *testing.T) { + factory := mocks.NewAbstractFactoryMaps(t) + templateRow := map[string]interface{}{ + "order": 1.0, + } + + doc, err := rowmapper.NewRow(templateRow, "", factory) + + assert.Nil(t, err) + assert.Equal(t, 0.0, doc.Height) + }) + t.Run("when invalid height is sent, should return an error", func(t *testing.T) { + factory := mocks.NewAbstractFactoryMaps(t) + templateRow := map[string]interface{}{ + "height": "invalid", + } + + doc, err := rowmapper.NewRow(templateRow, "", factory) + + assert.Nil(t, doc) + assert.NotNil(t, err) + }) + t.Run("when an invalid field is sent, should return an error", func(t *testing.T) { + factory := mocks.NewAbstractFactoryMaps(t) + templateRow := map[string]interface{}{ + "invalid_field": "invalid", + } + + doc, err := rowmapper.NewRow(templateRow, "", factory) + + assert.Nil(t, doc) + assert.NotNil(t, err) + }) + t.Run("when an invalid col is sent, should return an error", func(t *testing.T) { + factory := mocks.NewAbstractFactoryMaps(t) + templateRow := map[string]interface{}{ + "cols": "invalid", + } + + doc, err := rowmapper.NewRow(templateRow, "", factory) + + assert.Nil(t, doc) + assert.NotNil(t, err) + }) + t.Run("when the order field is not sent, should return an error", func(t *testing.T) { + templateRows := map[string]interface{}{} + factory := mocks.NewAbstractFactoryMaps(t) + + _, err := rowmapper.NewRow(templateRows, "test", factory) + + assert.NotNil(t, err) + }) + t.Run("when the order field is less than 1, should return an error", func(t *testing.T) { + templateRows := map[string]interface{}{ + "order": 0.0, + } + factory := mocks.NewAbstractFactoryMaps(t) + + _, err := rowmapper.NewRow(templateRows, "test", factory) + + assert.NotNil(t, err) + }) + t.Run("when invalid props is sent, should return an erros", func(t *testing.T) { + templateRow := map[string]interface{}{ + "height": 10.0, + "props": 1, + "order": 1.0, + } + factory := mocks.NewAbstractFactoryMaps(t) + + _, err := rowmapper.NewRow(templateRow, "test", factory) + + assert.NotNil(t, err) + }) + t.Run("when valid props is sent, should create row", func(t *testing.T) { + templateRow := map[string]interface{}{ + "height": 10.0, + "props": map[string]interface{}{ + "line_style": "solid", + "border_type": "top", + }, + "order": 1.0, + } + factory := mocks.NewAbstractFactoryMaps(t) + + _, err := rowmapper.NewRow(templateRow, "test_row", factory) + + assert.Nil(t, err) + }) +} + +func TestGenerate(t *testing.T) { + t.Run("when content no has source_key, should send an empty list", func(t *testing.T) { + content := map[string]interface{}{"source_key_test": 1} + factory := mocks.NewAbstractFactoryMaps(t) + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateRow(10.0, (*propsmapper.Cell)(nil)).Return(nil, nil) + component := mocks.NewComponentmapper(t) + component.EXPECT().Generate(map[string]interface{}{}, provider).Return(nil, nil) + + row := rowmapper.Row{Height: 10, Cols: []mappers.Componentmapper{component}, Factory: factory, SourceKey: "test"} + newRow, err := row.Generate(content, provider) + + assert.NotNil(t, newRow) + assert.Nil(t, err) + }) + t.Run("when row no has row, it should no sent row", func(t *testing.T) { + content := map[string]interface{}{"content": map[string]interface{}{"text": "value"}} + factory := mocks.NewAbstractFactoryMaps(t) + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateRow(10.0, (*propsmapper.Cell)(nil)).Return(nil, nil) + + row := rowmapper.Row{Height: 10.0, Cols: make([]mappers.Componentmapper, 0), Factory: factory, SourceKey: "content"} + _, err := row.Generate(content, provider) + + assert.Nil(t, err) + }) + t.Run("when is not possible generate components, should return an error", func(t *testing.T) { + content := map[string]interface{}{"content": map[string]interface{}{"text": "value"}} + factory := mocks.NewAbstractFactoryMaps(t) + provider := mocks.NewProcessorProvider(t) + component := mocks.NewComponentmapper(t) + component.EXPECT().Generate(mock.Anything, provider).Return(nil, fmt.Errorf("any")) + + row := rowmapper.Row{Height: 10.0, Cols: []mappers.Componentmapper{component}, Factory: factory, SourceKey: "content"} + _, err := row.Generate(content, provider) + + assert.NotNil(t, err) + }) + t.Run("when is not possible generate row, should return an error", func(t *testing.T) { + content := map[string]interface{}{"content": map[string]interface{}{"text": "value"}} + factory := mocks.NewAbstractFactoryMaps(t) + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateRow(10.0, (*propsmapper.Cell)(nil)).Return(nil, fmt.Errorf("any")) + + row := rowmapper.Row{Height: 10.0, Cols: make([]mappers.Componentmapper, 0), Factory: factory, SourceKey: "content"} + _, err := row.Generate(content, provider) + + assert.NotNil(t, err) + }) +} diff --git a/pkg/processor/mappers/components/signaturemapper/signature.go b/pkg/processor/mappers/components/signaturemapper/signature.go new file mode 100644 index 00000000..84deec61 --- /dev/null +++ b/pkg/processor/mappers/components/signaturemapper/signature.go @@ -0,0 +1,136 @@ +// Package signature implements creation of signatures. +package signaturemapper + +import ( + "fmt" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/order" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" +) + +type Signature struct { + SourceKey string + Value string + Props *propsmapper.Signature + Order int +} + +func NewSignature(code interface{}) (*Signature, error) { + signatureMap, ok := code.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure signature can be converted to map[string] interface{}") + } + + signature := &Signature{} + if err := signature.addFields(signatureMap); err != nil { + return nil, err + } + if err := signature.validateFields(); err != nil { + return nil, err + } + + return signature, nil +} + +// addFields is responsible for adding the signature fields according to +// the properties informed in the map +func (s *Signature) addFields(signatureMap map[string]interface{}) error { + order, err := order.SetPageOrder(&signatureMap, "signature", s.SourceKey) + if err != nil { + return err + } + s.Order = order + fieldMappers := s.getFieldMappers() + + for templateName, template := range signatureMap { + mapper, ok := fieldMappers[templateName] + if !ok { + return fmt.Errorf("the field %s present in the signature cannot be mapped to any valid field", templateName) + } + err := mapper(template) + if err != nil { + return err + } + } + return nil +} + +// GetOrder is responsible for returning the component's defined order +func (s *Signature) GetOrder() int { + return s.Order +} + +// getFieldMappers is responsible for defining which methods are responsible for assembling which components. +// To do this, the component name is linked to a function in a Map. +func (s *Signature) getFieldMappers() map[string]func(interface{}) error { + return map[string]func(interface{}) error{ + "source_key": s.setSourceKey, + "value": s.setValue, + "props": s.setProps, + } +} + +func (s *Signature) setSourceKey(template interface{}) error { + sourceKey, ok := template.(string) + if !ok { + return fmt.Errorf("source_key cannot be converted to a string") + } + s.SourceKey = sourceKey + return nil +} + +func (s *Signature) setValue(template interface{}) error { + value, ok := template.(string) + if !ok { + return fmt.Errorf("value cannot be converted to a string") + } + s.Value = value + return nil +} + +func (s *Signature) setProps(template interface{}) error { + props, err := propsmapper.NewSignature(template) + if err != nil { + return err + } + s.Props = props + return nil +} + +func (s *Signature) validateFields() error { + if s.Value == "" && s.SourceKey == "" { + return fmt.Errorf("no value passed for signature. Add the 'source_key' or a value") + } + return nil +} + +func (s *Signature) getSignature(content map[string]interface{}) (string, error) { + if s.Value != "" { + return s.Value, nil + } + signatureFound, ok := content[s.SourceKey] + if !ok { + return "", fmt.Errorf("signature requires a source key named %s, but it was not found", s.SourceKey) + } + signatureValid, ok := signatureFound.(string) + if !ok { + return "", fmt.Errorf("unable to generate signature, invalid value. source key %s", s.SourceKey) + } + return signatureValid, nil +} + +func (s *Signature) Generate(content map[string]interface{}, provider processorprovider.ProcessorProvider) ( + []processorprovider.ProviderComponent, error, +) { + signature, err := s.getSignature(content) + if err != nil { + return nil, err + } + s.Value = signature + + if s.Props != nil { + return []processorprovider.ProviderComponent{provider.CreateSignature(s.Value, s.Props)}, nil + } + return []processorprovider.ProviderComponent{provider.CreateSignature(s.Value)}, nil +} diff --git a/pkg/processor/mappers/components/signaturemapper/signature_test.go b/pkg/processor/mappers/components/signaturemapper/signature_test.go new file mode 100644 index 00000000..8ee19871 --- /dev/null +++ b/pkg/processor/mappers/components/signaturemapper/signature_test.go @@ -0,0 +1,171 @@ +package signaturemapper_test + +import ( + "testing" + + "github.com/johnfercher/maroto/v2/mocks" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/signaturemapper" + "github.com/stretchr/testify/assert" +) + +func TestQrcodeGetOrder(t *testing.T) { + t.Run("when getOrder is called, should return defined order", func(t *testing.T) { + templateRows := map[string]interface{}{ + "order": 10.0, + "value": "test", + } + + doc, _ := signaturemapper.NewSignature(templateRows) + + assert.Equal(t, 10, doc.GetOrder()) + }) +} + +func TestNewSignature(t *testing.T) { + t.Run("when invalid signature is sent, should return an error", func(t *testing.T) { + signatureTemplate := 1 + + signature, err := signaturemapper.NewSignature(signatureTemplate) + + assert.Nil(t, signature) + assert.NotNil(t, err) + }) + t.Run("when props is not sent, signature is created", func(t *testing.T) { + signatureTemplate := map[string]interface{}{ + "value": "123456789", + "order": 1.0, + } + + signature, err := signaturemapper.NewSignature(signatureTemplate) + + assert.Nil(t, err) + assert.NotNil(t, signature) + }) + t.Run("when invalid props is sent, should return an error", func(t *testing.T) { + signatureTemplate := map[string]interface{}{ + "props": 1, + "value": "123456789", + "order": 1.0, + } + + signature, err := signaturemapper.NewSignature(signatureTemplate) + + assert.Nil(t, signature) + assert.NotNil(t, err) + }) + t.Run("when invalid field is sent, should return an error", func(t *testing.T) { + signatureTemplate := map[string]interface{}{ + "invalid_field": 1, + "order": 1.0, + } + + signature, err := signaturemapper.NewSignature(signatureTemplate) + + assert.Nil(t, signature) + assert.NotNil(t, err) + }) + t.Run("when source_key and value are not sent, should return an error", func(t *testing.T) { + signatureTemplate := map[string]interface{}{} + + signature, err := signaturemapper.NewSignature(signatureTemplate) + + assert.Nil(t, signature) + assert.NotNil(t, err) + }) + t.Run("when invalid value is sent, should return an error", func(t *testing.T) { + signatureTemplate := map[string]interface{}{ + "value": 123, + "order": 1.0, + } + + signature, err := signaturemapper.NewSignature(signatureTemplate) + + assert.Nil(t, signature) + assert.NotNil(t, err) + }) + t.Run("when invalid source_key is sent, should return an error", func(t *testing.T) { + signatureTemplate := map[string]interface{}{ + "source_key": 123, + "order": 1.0, + } + + signature, err := signaturemapper.NewSignature(signatureTemplate) + + assert.Nil(t, signature) + assert.NotNil(t, err) + }) + t.Run("when value is not sent, should add source key", func(t *testing.T) { + signatureTemplate := map[string]interface{}{ + "source_key": "source", + "order": 1.0, + } + + signature, err := signaturemapper.NewSignature(signatureTemplate) + + assert.Nil(t, err) + assert.Equal(t, signature.SourceKey, "source") + }) + + t.Run("when source_key is not sent, should add code", func(t *testing.T) { + signatureTemplate := map[string]interface{}{ + "value": "value", + "order": 1.0, + } + + signature, err := signaturemapper.NewSignature(signatureTemplate) + + assert.Nil(t, err) + assert.Equal(t, signature.Value, "value") + }) +} + +func TestGenerate(t *testing.T) { + t.Run("if source key is not found, should return an error", func(t *testing.T) { + content := map[string]interface{}{} + provider := mocks.NewProcessorProvider(t) + + signature := signaturemapper.Signature{SourceKey: "code"} + component, err := signature.Generate(content, provider) + + assert.Nil(t, component) + assert.NotNil(t, err) + }) + t.Run("if source key content is not valid, should return an error", func(t *testing.T) { + content := map[string]interface{}{ + "value": 1, + } + provider := mocks.NewProcessorProvider(t) + + signature := signaturemapper.Signature{SourceKey: "value"} + component, err := signature.Generate(content, provider) + + assert.Nil(t, component) + assert.NotNil(t, err) + }) + t.Run("If the signature has no props, the props will not be sent", func(t *testing.T) { + content := map[string]interface{}{ + "value": "signature", + } + + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateSignature("signature").Return(nil) + + signature := signaturemapper.Signature{SourceKey: "value"} + _, err := signature.Generate(content, provider) + + assert.Nil(t, err) + provider.AssertNumberOfCalls(t, "CreateSignature", 1) + }) + t.Run("when valid code is sent, should generate signature", func(t *testing.T) { + content := map[string]interface{}{} + + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateSignature("signature").Return(nil) + + signature := signaturemapper.Signature{Value: "signature"} + _, err := signature.Generate(content, provider) + + assert.Nil(t, err) + provider.AssertNumberOfCalls(t, "CreateSignature", 1) + }) +} diff --git a/pkg/processor/mappers/components/textmapper/text.go b/pkg/processor/mappers/components/textmapper/text.go new file mode 100644 index 00000000..0521786d --- /dev/null +++ b/pkg/processor/mappers/components/textmapper/text.go @@ -0,0 +1,135 @@ +package textmapper + +import ( + "fmt" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/order" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" +) + +type Text struct { + SourceKey string + Value string + Props *propsmapper.Text + Order int +} + +func NewText(templateText interface{}) (*Text, error) { + textMap, ok := templateText.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure text can be converted to map[string] interface{}") + } + + text := &Text{} + if err := text.addFields(textMap); err != nil { + return nil, err + } + if err := text.validateFields(); err != nil { + return nil, err + } + + return text, nil +} + +// addFields is responsible for adding the text fields according to +// the properties informed in the map +func (t *Text) addFields(valueMap map[string]interface{}) error { + order, err := order.SetPageOrder(&valueMap, "text", t.SourceKey) + if err != nil { + return err + } + t.Order = order + fieldMappers := t.getFieldMappers() + + for templateName, template := range valueMap { + mapper, ok := fieldMappers[templateName] + if !ok { + return fmt.Errorf("the field %s present in the text cannot be mapped to any valid field", templateName) + } + err := mapper(template) + if err != nil { + return err + } + } + return nil +} + +// GetOrder is responsible for returning the component's defined order +func (t *Text) GetOrder() int { + return t.Order +} + +// getFieldMappers is responsible for defining which methods are responsible for assembling which components. +// To do this, the component name is linked to a function in a Map. +func (t *Text) getFieldMappers() map[string]func(interface{}) error { + return map[string]func(interface{}) error{ + "source_key": t.setSourceKey, + "value": t.setValue, + "props": t.setProps, + } +} + +func (t *Text) setSourceKey(template interface{}) error { + sourceKey, ok := template.(string) + if !ok { + return fmt.Errorf("source_key cannot be converted to a string") + } + t.SourceKey = sourceKey + return nil +} + +func (t *Text) setValue(template interface{}) error { + value, ok := template.(string) + if !ok { + return fmt.Errorf("value cannot be converted to a string") + } + t.Value = value + return nil +} + +func (t *Text) setProps(template interface{}) error { + props, err := propsmapper.NewText(template) + if err != nil { + return err + } + t.Props = props + return nil +} + +func (t *Text) validateFields() error { + if t.Value == "" && t.SourceKey == "" { + return fmt.Errorf("no value passed for text. Add the 'source_key' or a value") + } + return nil +} + +func (t *Text) getValue(content map[string]interface{}) (string, error) { + if t.SourceKey == "" { + return t.Value, nil + } + textFound, ok := content[t.SourceKey] + if !ok { + return "", fmt.Errorf("text requires a source key named %s, but it was not found", t.SourceKey) + } + textValid, ok := textFound.(string) + if !ok { + return "", fmt.Errorf("unable to generate text, invalid value. source key %s", t.SourceKey) + } + return textValid, nil +} + +func (t *Text) Generate(content map[string]interface{}, provider processorprovider.ProcessorProvider) ( + []processorprovider.ProviderComponent, error, +) { + signature, err := t.getValue(content) + if err != nil { + return nil, err + } + t.Value = signature + + if t.Props != nil { + return []processorprovider.ProviderComponent{provider.CreateText(t.Value, t.Props)}, nil + } + return []processorprovider.ProviderComponent{provider.CreateText(t.Value)}, nil +} diff --git a/pkg/processor/mappers/components/textmapper/text_test.go b/pkg/processor/mappers/components/textmapper/text_test.go new file mode 100644 index 00000000..e4c0d8a7 --- /dev/null +++ b/pkg/processor/mappers/components/textmapper/text_test.go @@ -0,0 +1,174 @@ +package textmapper_test + +import ( + "testing" + + "github.com/johnfercher/maroto/v2/mocks" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/components/textmapper" + "github.com/stretchr/testify/assert" +) + +func TestQrcodeGetOrder(t *testing.T) { + t.Run("when getOrder is called, should return defined order", func(t *testing.T) { + templateRows := map[string]interface{}{ + "order": 10.0, + "value": "text", + } + + doc, _ := textmapper.NewText(templateRows) + + assert.Equal(t, 10, doc.GetOrder()) + }) +} + +func TestNewText(t *testing.T) { + t.Run("when invalid text is sent, should return an error", func(t *testing.T) { + textTemplate := 1 + + text, err := textmapper.NewText(textTemplate) + + assert.Nil(t, text) + assert.NotNil(t, err) + }) + t.Run("when props is not sent, text is created", func(t *testing.T) { + textTemplate := map[string]interface{}{ + "value": "123456789", + "order": 1.0, + } + + text, err := textmapper.NewText(textTemplate) + + assert.Nil(t, err) + assert.NotNil(t, text) + }) + t.Run("when invalid props is sent, should return an error", func(t *testing.T) { + textTemplate := map[string]interface{}{ + "props": 1, + "value": "123456789", + "order": 1.0, + } + + text, err := textmapper.NewText(textTemplate) + + assert.Nil(t, text) + assert.NotNil(t, err) + }) + t.Run("when invalid field is sent, should return an error", func(t *testing.T) { + textTemplate := map[string]interface{}{ + "invalid_field": 1, + "value": "123456789", + "order": 1.0, + } + + text, err := textmapper.NewText(textTemplate) + + assert.Nil(t, text) + assert.NotNil(t, err) + }) + t.Run("when source_key and value are not sent, should return an error", func(t *testing.T) { + textTemplate := map[string]interface{}{ + "order": 1.0, + } + + text, err := textmapper.NewText(textTemplate) + + assert.Nil(t, text) + assert.NotNil(t, err) + }) + t.Run("when invalid value is sent, should return an error", func(t *testing.T) { + textTemplate := map[string]interface{}{ + "value": 123, + "order": 1.0, + } + + text, err := textmapper.NewText(textTemplate) + + assert.Nil(t, text) + assert.NotNil(t, err) + }) + t.Run("when invalid source_key is sent, should return an error", func(t *testing.T) { + textTemplate := map[string]interface{}{ + "source_key": 123, + "order": 1.0, + } + + text, err := textmapper.NewText(textTemplate) + + assert.Nil(t, text) + assert.NotNil(t, err) + }) + t.Run("when value is not sent, should add source key", func(t *testing.T) { + textTemplate := map[string]interface{}{ + "source_key": "source", + "order": 1.0, + } + + text, err := textmapper.NewText(textTemplate) + + assert.Nil(t, err) + assert.Equal(t, text.SourceKey, "source") + }) + + t.Run("when source_key is not sent, should add value", func(t *testing.T) { + textTemplate := map[string]interface{}{ + "value": "value", + "order": 1.0, + } + + text, err := textmapper.NewText(textTemplate) + + assert.Nil(t, err) + assert.Equal(t, text.Value, "value") + }) +} + +func TestGenerate(t *testing.T) { + t.Run("if source key is not found, should return an error", func(t *testing.T) { + content := map[string]interface{}{} + provider := mocks.NewProcessorProvider(t) + + text := textmapper.Text{SourceKey: "text"} + component, err := text.Generate(content, provider) + + assert.Nil(t, component) + assert.NotNil(t, err) + }) + t.Run("if source key content is not valid, should return an error", func(t *testing.T) { + content := map[string]interface{}{ + "value": 1, + } + provider := mocks.NewProcessorProvider(t) + + text := textmapper.Text{SourceKey: "value"} + component, err := text.Generate(content, provider) + + assert.Nil(t, component) + assert.NotNil(t, err) + }) + t.Run("If the text has no props, the props will not be sent", func(t *testing.T) { + content := map[string]interface{}{ + "value": "text", + } + + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateText("text").Return(nil) + + text := textmapper.Text{SourceKey: "value"} + _, err := text.Generate(content, provider) + + assert.Nil(t, err) + provider.AssertNumberOfCalls(t, "CreateText", 1) + }) + t.Run("when valid text is sent, should generate text", func(t *testing.T) { + content := map[string]interface{}{} + + provider := mocks.NewProcessorProvider(t) + provider.EXPECT().CreateText("text").Return(nil) + + text := textmapper.Text{Value: "text"} + _, err := text.Generate(content, provider) + + assert.Nil(t, err) + provider.AssertNumberOfCalls(t, "CreateText", 1) + }) +} diff --git a/pkg/processor/mappers/documentmapper/document.go b/pkg/processor/mappers/documentmapper/document.go new file mode 100644 index 00000000..909a028c --- /dev/null +++ b/pkg/processor/mappers/documentmapper/document.go @@ -0,0 +1,258 @@ +// documentmapper is the package responsible for mapping pdf settings +package documentmapper + +import ( + "fmt" + "strings" + + "github.com/johnfercher/maroto/v2/pkg/processor/mappers" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/buildermapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" +) + +type Document struct { + factory mappers.AbstractFactoryMaps + Builder buildermapper.Builder + Header []mappers.Componentmapper + Footer []mappers.Componentmapper + Pages []mappers.Componentmapper +} + +// NewPdf is responsible for creating the pdf template +// parse the model and create the pdf object +func NewPdf(template map[string]any, factory mappers.AbstractFactoryMaps) (*Document, error) { + newPdf := Document{ + factory: factory, Builder: buildermapper.Builder{}, Pages: make([]mappers.Componentmapper, 0), + Header: make([]mappers.Componentmapper, 0), Footer: make([]mappers.Componentmapper, 0), + } + + err := newPdf.addComponentsToPdf(template) + if err != nil { + return nil, err + } + + return &newPdf, nil +} + +// addComponentsToPdf is responsible for adding all the components that are part of the template to the PDF. +// This is the method where the components that are part of the PDF are created. +func (d *Document) addComponentsToPdf(templates map[string]interface{}) error { + fieldMappers := d.getFieldMappers() + + for field, template := range templates { + mapper, ok := fieldMappers[field] + if !ok { + return fmt.Errorf("the field %s present in the template cannot be mapped to any valid component", field) + } + err := mapper(template) + if err != nil { + return err + } + } + return nil +} + +// getFieldMappers is responsible for defining which methods are responsible for assembling which components. +// To do this, the component name is linked to a function in a Map. +func (d *Document) getFieldMappers() map[string]func(interface{}) error { + return map[string]func(interface{}) error{ + "builder": d.setBuilder, + "header": d.setHeader, + "footer": d.setFooter, + "pages": d.setPages, + } +} + +// setBuilder is responsible for factories builder information +func (d *Document) setBuilder(builderDoc interface{}) error { + builder, err := buildermapper.NewBuilder(builderDoc) + if err != nil { + return err + } + + d.Builder = *builder + return nil +} + +// setHeader is responsible for factory the header +func (d *Document) setHeader(rowsDoc interface{}) error { + rowsTemplate, ok := rowsDoc.(map[string]interface{}) + if !ok { + return fmt.Errorf("header cannot be deserialized, ensure header has an array of rows") + } + + for templateKey, rowTemplate := range rowsTemplate { + row, err := d.factory.NewRow(rowTemplate, templateKey) + if err != nil { + return err + } + d.Header = append(d.Header, row) + } + + return nil +} + +// setFooter is responsible for factory the footer +func (d *Document) setFooter(rowsDoc interface{}) error { + rowsTemplate, ok := rowsDoc.(map[string]interface{}) + if !ok { + return fmt.Errorf("footer cannot be deserialized, ensure footer has an array of rows") + } + + for templateKey, rowTemplate := range rowsTemplate { + row, err := d.factory.NewRow(rowTemplate, templateKey) + if err != nil { + return err + } + d.Footer = append(d.Footer, row) + } + + return nil +} + +// setPages is responsible for factory the pages. +// pages can be a list of pages or just one page +func (d *Document) setPages(pagesDoc interface{}) error { + templatePage, ok := pagesDoc.(map[string]interface{}) + if !ok { + return fmt.Errorf("ensure pages can be converted to map[string] interface{}") + } + + d.Pages = make([]mappers.Componentmapper, len(templatePage)) + for templateName, template := range templatePage { + page, err := d.factoryPage(template, templateName) + if err != nil { + return err + } + if err := d.addPage(page); err != nil { + return err + } + } + + return nil +} + +// addPage is responsible for validating and adding the page to the template +func (d *Document) addPage(page mappers.OrderedComponents) error { + order := page.GetOrder() + if page.GetOrder() > len(d.Pages) { + return fmt.Errorf("component order cannot be greater than %d, this is the number of components in the template", len(d.Pages)) + } + if d.Pages[order-1] != nil { + return fmt.Errorf("cannot create document template, component order cannot be repeated") + } + + d.Pages[order-1] = page + return nil +} + +// factoryPage is responsible for making a template of a page or a list of pages +func (d *Document) factoryPage(template interface{}, templateName string) (mappers.OrderedComponents, error) { + var page mappers.OrderedComponents + var err error + + if strings.HasPrefix(templateName, "list") { + page, err = d.factory.NewList(template, templateName, d.factory.NewPage) + } else { + page, err = d.factory.NewPage(template, templateName) + } + + if err != nil { + return nil, err + } + return page, nil +} + +func (d *Document) GetBuilderCfg() *buildermapper.Builder { + return &d.Builder +} + +// getContent is responsible for obtaining a content with a matching key, when the content is not found, +// an empty array is returned +func (d *Document) getContent(content map[string]interface{}, key string) (map[string]interface{}, error) { + doc, ok := content[key] + if ok { + docArr, ok := doc.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure that the contents of the %s can be converted to map[string]interface{}", key) + } + return docArr, nil + } + return make(map[string]interface{}, 0), nil +} + +// generatePages is responsible for creating and adding pages, if the content does not have a page field +// an empty array is sent to the page +func (d *Document) generatePages(content map[string]interface{}, provider processorprovider.ProcessorProvider) error { + pageContent, err := d.getContent(content, "pages") + if err != nil { + return err + } + + pagesComponents := make([]processorprovider.ProviderComponent, 0, len(d.Pages)) + for _, pageTemplate := range d.Pages { + page, err := pageTemplate.Generate(pageContent, provider) + if err != nil { + return err + } + pagesComponents = append(pagesComponents, page...) + } + + _, err = provider.AddPages(pagesComponents...) + return err +} + +// generateRows is responsible for creating row components, it will extract the content (if it exists) +// and send this content to rows +func (d *Document) generateRows(content map[string]interface{}, provider processorprovider.ProcessorProvider, + sourceKey string, templateRows ...mappers.Componentmapper, +) ([]processorprovider.ProviderComponent, error) { + headerContent, err := d.getContent(content, sourceKey) + if err != nil { + return nil, err + } + + rows := make([]processorprovider.ProviderComponent, 0, len(templateRows)) + for _, row := range templateRows { + componentRow, err := row.Generate(headerContent, provider) + if err != nil { + return nil, err + } + rows = append(rows, componentRow...) + } + return rows, nil +} + +// generate is responsible for the builder pdf according to the submitted content +func (d *Document) Generate(content map[string]interface{}, + provider processorprovider.ProcessorProvider) (*processorprovider.ProcessorProvider, error, +) { + if len(d.Header) > 0 { + header, err := d.generateRows(content, provider, "header", d.Header...) + if err != nil { + return nil, err + } + _, err = provider.AddHeader(header...) + if err != nil { + return nil, err + } + } + + if len(d.Footer) > 0 { + footer, err := d.generateRows(content, provider, "footer", d.Footer...) + if err != nil { + return nil, err + } + _, err = provider.AddFooter(footer...) + if err != nil { + return nil, err + } + } + + if len(d.Pages) > 0 { + if err := d.generatePages(content, provider); err != nil { + return nil, err + } + } + return &provider, nil +} diff --git a/pkg/processor/mappers/documentmapper/document_test.go b/pkg/processor/mappers/documentmapper/document_test.go new file mode 100644 index 00000000..89511af9 --- /dev/null +++ b/pkg/processor/mappers/documentmapper/document_test.go @@ -0,0 +1,390 @@ +package documentmapper_test + +import ( + "fmt" + "testing" + + "github.com/johnfercher/maroto/v2/internal/fixture" + "github.com/johnfercher/maroto/v2/mocks" + "github.com/johnfercher/maroto/v2/pkg/processor/deserializer" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/documentmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestNewPdf(t *testing.T) { + t.Run("when builder is sent, should set builder", func(t *testing.T) { + builderDocument := ` + { + "builder": {"concurrent_mode": 10} + } + ` + factory := mocks.NewAbstractFactoryMaps(t) + + template, err := deserializer.NewJSONDeserializer().Deserialize(builderDocument) + assert.Nil(t, err) + + doc, err := documentmapper.NewPdf(template, factory) + assert.Nil(t, err) + assert.Equal(t, doc.Builder.ConcurrentMode, 10) + }) + + t.Run("when an invalid builder is passed, should return an error", func(t *testing.T) { + builderDocument := `{"builder": 10}` + factory := mocks.NewAbstractFactoryMaps(t) + + template, err := deserializer.NewJSONDeserializer().Deserialize(builderDocument) + assert.Nil(t, err) + + doc, err := documentmapper.NewPdf(template, factory) + + assert.NotNil(t, err) + assert.Nil(t, doc) + }) + + t.Run("When a 2-rows header is sent, should set the header", func(t *testing.T) { + builderDocument := ` + {"header": { + "row_template_1": {}, + "row_template_2": {} + }} + ` + validRow := fixture.MapperRow() + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewRow", mock.Anything, mock.Anything).Return(validRow, nil) + + template, err := deserializer.NewJSONDeserializer().Deserialize(builderDocument) + assert.Nil(t, err) + + doc, err := documentmapper.NewPdf(template, factory) + + assert.Nil(t, err) + assert.Equal(t, 2, len(doc.Header)) + }) + + t.Run("when an invalid header is passed, should return an error", func(t *testing.T) { + builderDocument := `{"header": 1}` + factory := mocks.NewAbstractFactoryMaps(t) + + template, err := deserializer.NewJSONDeserializer().Deserialize(builderDocument) + assert.Nil(t, err) + + _, err = documentmapper.NewPdf(template, factory) + assert.NotNil(t, err) + }) + + t.Run("When a 2-rows footer is sent, should set the footer", func(t *testing.T) { + builderDocument := ` + {"footer": { + "row_template_1": {}, + "row_template_2": {} + }} + ` + validRow := fixture.MapperRow() + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewRow", mock.Anything, mock.Anything).Return(validRow, nil) + + template, err := deserializer.NewJSONDeserializer().Deserialize(builderDocument) + assert.Nil(t, err) + + doc, err := documentmapper.NewPdf(template, factory) + + assert.Nil(t, err) + assert.Equal(t, 2, len(doc.Footer)) + }) + + t.Run("when an invalid footer is passed, should return an error", func(t *testing.T) { + builderDocument := `{"footer": 1}` + factory := mocks.NewAbstractFactoryMaps(t) + + template, err := deserializer.NewJSONDeserializer().Deserialize(builderDocument) + assert.Nil(t, err) + + _, err = documentmapper.NewPdf(template, factory) + + assert.NotNil(t, err) + }) + + t.Run("when the template order is greater than the number of pages, an error should be returned", func(t *testing.T) { + builderDocument := `{"pages": {"page_template_1":{}}}` + orderedComponent := mocks.NewOrderedComponents(t) + orderedComponent.EXPECT().GetOrder().Return(2) + + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewPage", mock.Anything, "page_template_1").Return(orderedComponent, nil) + + template, err := deserializer.NewJSONDeserializer().Deserialize(builderDocument) + assert.Nil(t, err) + + _, err = documentmapper.NewPdf(template, factory) + + assert.NotNil(t, err) + }) + + t.Run("when the template order is repeated, an error should be returned", func(t *testing.T) { + builderDocument := `{"pages": {"page_template_2":{}, "page_template_1":{}}}` + orderedComponent := mocks.NewOrderedComponents(t) + orderedComponent.EXPECT().GetOrder().Return(2) + + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewPage", mock.Anything, "page_template_1").Return(orderedComponent, nil) + factory.On("NewPage", mock.Anything, "page_template_2").Return(orderedComponent, nil) + + template, err := deserializer.NewJSONDeserializer().Deserialize(builderDocument) + assert.Nil(t, err) + + _, err = documentmapper.NewPdf(template, factory) + + assert.NotNil(t, err) + }) + + t.Run("when 2 pages are submitted, should add the 2 pages in the correct order", func(t *testing.T) { + builderDocument := ` + {"pages": { + "page_template_1":{}, + "page_template_2":{} + }} + ` + orderedComponent1 := mocks.NewOrderedComponents(t) + orderedComponent1.EXPECT().GetOrder().Return(1) + orderedComponent2 := mocks.NewOrderedComponents(t) + orderedComponent2.EXPECT().GetOrder().Return(2) + + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewPage", mock.Anything, "page_template_1").Return(orderedComponent1, nil) + factory.On("NewPage", mock.Anything, "page_template_2").Return(orderedComponent2, nil) + + template, err := deserializer.NewJSONDeserializer().Deserialize(builderDocument) + assert.Nil(t, err) + + doc, err := documentmapper.NewPdf(template, factory) + + assert.Nil(t, err) + assert.Equal(t, len(doc.Pages), 2) + assert.Equal(t, orderedComponent1, doc.Pages[0]) + }) + + t.Run("when 2 pages are sent, it should add 2 pages to the document", func(t *testing.T) { + builderDocument := ` + {"pages": { + "page_template_1":{}, + "page_template_2":{} + }} + ` + orderedComponent1 := mocks.NewOrderedComponents(t) + orderedComponent1.EXPECT().GetOrder().Return(1) + orderedComponent2 := mocks.NewOrderedComponents(t) + orderedComponent2.EXPECT().GetOrder().Return(2) + + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewPage", mock.Anything, "page_template_1").Return(orderedComponent1, nil) + factory.On("NewPage", mock.Anything, "page_template_2").Return(orderedComponent2, nil) + + template, err := deserializer.NewJSONDeserializer().Deserialize(builderDocument) + assert.Nil(t, err) + + doc, err := documentmapper.NewPdf(template, factory) + + assert.Nil(t, err) + assert.Equal(t, len(doc.Pages), 2) + }) + + t.Run("when 1 list is sent, it should add 1 list to the document", func(t *testing.T) { + builderDocument := ` + {"pages": { + "list_template_1":{} + }} + ` + orderedComponent1 := mocks.NewOrderedComponents(t) + orderedComponent1.EXPECT().GetOrder().Return(1) + + factory := mocks.NewAbstractFactoryMaps(t) + factory.On("NewList", mock.Anything, "list_template_1", mock.Anything).Return(orderedComponent1, nil) + + template, err := deserializer.NewJSONDeserializer().Deserialize(builderDocument) + assert.Nil(t, err) + + doc, err := documentmapper.NewPdf(template, factory) + + assert.Nil(t, err) + assert.Equal(t, len(doc.Pages), 1) + }) + + t.Run("when an invalid page is sent, it should return an error", func(t *testing.T) { + builderDocument := `{"pages": 1}` + factory := mocks.NewAbstractFactoryMaps(t) + + template, err := deserializer.NewJSONDeserializer().Deserialize(builderDocument) + assert.Nil(t, err) + + _, err = documentmapper.NewPdf(template, factory) + assert.NotNil(t, err) + }) +} + +func TestGenerate(t *testing.T) { + t.Run("when document have no template, should not set template ", func(t *testing.T) { + fixContent := make(map[string]interface{}) + mockProvider := mocks.NewProcessorProvider(t) + + doc := documentmapper.Document{ + Pages: make([]mappers.Componentmapper, 0), Header: make([]mappers.Componentmapper, 0), + Footer: make([]mappers.Componentmapper, 0), + } + provider, err := doc.Generate(fixContent, mockProvider) + + assert.Nil(t, err) + assert.NotNil(t, provider) + }) + t.Run("when templates have no content, should generate templates with empty content", func(t *testing.T) { + fixContent := map[string]interface{}{"test": "any"} + + mockProviderComponents := []processorprovider.ProviderComponent{mocks.NewProviderComponent(t)} + mockComponent := mocks.NewComponentmapper(t) + mockComponent.EXPECT().Generate(map[string]interface{}{}, mock.Anything).Return(mockProviderComponents, nil) + mockProvider := mocks.NewProcessorProvider(t) + mockProvider.EXPECT().AddPages(mockProviderComponents[0]).Return(mockProvider, nil) + mockProvider.EXPECT().AddHeader(mockProviderComponents[0]).Return(mockProvider, nil) + mockProvider.EXPECT().AddFooter(mockProviderComponents[0]).Return(mockProvider, nil) + + doc := documentmapper.Document{ + Pages: []mappers.Componentmapper{mockComponent}, Header: []mappers.Componentmapper{mockComponent}, + Footer: []mappers.Componentmapper{mockComponent}, + } + provider, err := doc.Generate(fixContent, mockProvider) + + assert.Nil(t, err) + assert.NotNil(t, provider) + }) + t.Run("when it is not possible to generate the page, it should return an error", func(t *testing.T) { + fixContent := map[string]interface{}{} + + mockComponent := mocks.NewComponentmapper(t) + mockComponent.EXPECT().Generate(map[string]interface{}{}, mock.Anything).Return(nil, fmt.Errorf("any")) + mockProvider := mocks.NewProcessorProvider(t) + + doc := documentmapper.Document{ + Pages: []mappers.Componentmapper{mockComponent}, Header: []mappers.Componentmapper{}, + Footer: []mappers.Componentmapper{}, + } + provider, err := doc.Generate(fixContent, mockProvider) + + assert.Nil(t, provider) + assert.NotNil(t, err) + }) + t.Run("when it is not possible to generate the header, it should return an error", func(t *testing.T) { + fixContent := map[string]interface{}{} + + mockComponent := mocks.NewComponentmapper(t) + mockComponent.EXPECT().Generate(map[string]interface{}{}, mock.Anything).Return(nil, fmt.Errorf("any")) + mockProvider := mocks.NewProcessorProvider(t) + + doc := documentmapper.Document{ + Pages: []mappers.Componentmapper{}, Header: []mappers.Componentmapper{mockComponent}, + Footer: []mappers.Componentmapper{}, + } + provider, err := doc.Generate(fixContent, mockProvider) + + assert.Nil(t, provider) + assert.NotNil(t, err) + }) + t.Run("when it is not possible to generate the footer, it should return an error", func(t *testing.T) { + fixContent := map[string]interface{}{} + + mockComponent := mocks.NewComponentmapper(t) + mockComponent.EXPECT().Generate(map[string]interface{}{}, mock.Anything).Return(nil, fmt.Errorf("any")) + mockProvider := mocks.NewProcessorProvider(t) + + doc := documentmapper.Document{ + Pages: []mappers.Componentmapper{}, Header: []mappers.Componentmapper{}, + Footer: []mappers.Componentmapper{mockComponent}, + } + provider, err := doc.Generate(fixContent, mockProvider) + + assert.Nil(t, provider) + assert.NotNil(t, err) + }) + t.Run("when it is not possible add the page to the document, it should return an error", func(t *testing.T) { + fixContent := map[string]interface{}{} + + mockProviderComponents := []processorprovider.ProviderComponent{mocks.NewProviderComponent(t)} + mockComponent := mocks.NewComponentmapper(t) + mockComponent.EXPECT().Generate(map[string]interface{}{}, mock.Anything).Return(mockProviderComponents, nil) + mockProvider := mocks.NewProcessorProvider(t) + mockProvider.EXPECT().AddPages(mockProviderComponents[0]).Return(nil, fmt.Errorf("any")) + + doc := documentmapper.Document{ + Pages: []mappers.Componentmapper{mockComponent}, Header: []mappers.Componentmapper{}, + Footer: []mappers.Componentmapper{}, + } + provider, err := doc.Generate(fixContent, mockProvider) + + assert.Nil(t, provider) + assert.NotNil(t, err) + }) + t.Run("when it is not possible add the header to the document, it should return an error", func(t *testing.T) { + fixContent := map[string]interface{}{} + + mockProviderComponents := []processorprovider.ProviderComponent{mocks.NewProviderComponent(t)} + mockComponent := mocks.NewComponentmapper(t) + mockComponent.EXPECT().Generate(map[string]interface{}{}, mock.Anything).Return(mockProviderComponents, nil) + mockProvider := mocks.NewProcessorProvider(t) + mockProvider.EXPECT().AddHeader(mockProviderComponents[0]).Return(nil, fmt.Errorf("any")) + + doc := documentmapper.Document{ + Pages: []mappers.Componentmapper{}, Header: []mappers.Componentmapper{mockComponent}, + Footer: []mappers.Componentmapper{}, + } + provider, err := doc.Generate(fixContent, mockProvider) + + assert.Nil(t, provider) + assert.NotNil(t, err) + }) + t.Run("when it is not possible add the footer to the document, it should return an error", func(t *testing.T) { + fixContent := map[string]interface{}{} + + mockProviderComponents := []processorprovider.ProviderComponent{mocks.NewProviderComponent(t)} + mockComponent := mocks.NewComponentmapper(t) + mockComponent.EXPECT().Generate(map[string]interface{}{}, mock.Anything).Return(mockProviderComponents, nil) + mockProvider := mocks.NewProcessorProvider(t) + mockProvider.EXPECT().AddFooter(mockProviderComponents[0]).Return(nil, fmt.Errorf("any")) + + doc := documentmapper.Document{ + Pages: []mappers.Componentmapper{}, Header: []mappers.Componentmapper{}, + Footer: []mappers.Componentmapper{mockComponent}, + } + provider, err := doc.Generate(fixContent, mockProvider) + + assert.Nil(t, provider) + assert.NotNil(t, err) + }) + t.Run("when document with page, header and footer is call, should generate document", func(t *testing.T) { + fixContent := map[string]interface{}{ + "header": map[string]interface{}{"row_header": "test"}, + "footer": map[string]interface{}{"row_footer": "test"}, + "pages": map[string]interface{}{"template_page_1": "test"}, + } + + mockProviderComponents := []processorprovider.ProviderComponent{mocks.NewProviderComponent(t)} + mockComponent := mocks.NewComponentmapper(t) + mockComponent.EXPECT().Generate(fixContent["header"], mock.Anything).Return(mockProviderComponents, nil) + mockComponent.EXPECT().Generate(fixContent["footer"], mock.Anything).Return(mockProviderComponents, nil) + mockComponent.EXPECT().Generate(fixContent["pages"], mock.Anything).Return(mockProviderComponents, nil) + mockProvider := mocks.NewProcessorProvider(t) + mockProvider.EXPECT().AddPages(mockProviderComponents[0]).Return(mockProvider, nil) + mockProvider.EXPECT().AddHeader(mockProviderComponents[0]).Return(mockProvider, nil) + mockProvider.EXPECT().AddFooter(mockProviderComponents[0]).Return(mockProvider, nil) + + doc := documentmapper.Document{ + Pages: []mappers.Componentmapper{mockComponent}, Header: []mappers.Componentmapper{mockComponent}, + Footer: []mappers.Componentmapper{mockComponent}, + } + provider, err := doc.Generate(fixContent, mockProvider) + + assert.Nil(t, err) + assert.NotNil(t, provider) + mockComponent.AssertNumberOfCalls(t, "Generate", 3) + }) +} diff --git a/pkg/processor/mappers/propsmapper/barcode.go b/pkg/processor/mappers/propsmapper/barcode.go new file mode 100644 index 00000000..2e14df58 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/barcode.go @@ -0,0 +1,40 @@ +package propsmapper + +import "fmt" + +// Barcode represents properties from a barcode inside a cell. +type Barcode struct { + // Left is the space between the left cell boundary to the barcode, if center is false. + Left float64 + // Top is space between the upper cell limit to the barcode, if center is false. + Top float64 + // Percent is how much the barcode will occupy the cell, + // ex 100%: The barcode will fulfill the entire cell + // ex 50%: The greater side from the barcode will have half the size of the cell. + Percent float64 + // Proportion is the proportion between size of the barcode. + // Ex: 16x9, 4x3... + Proportion Proportion + // Center define that the barcode will be vertically and horizontally centralized. + Center bool + // Type represents the barcode type. Default: code128 + Type string +} + +// NewBarcode is responsible for creating the barcode, if the font fields cannot be +// converted, an invalid value is set. +func NewBarcode(barcode interface{}) (*Barcode, error) { + barcodeMap, ok := barcode.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure barcode props can be converted to map[string] interface{}") + } + + return &Barcode{ + Left: *convertFields(barcodeMap["left"], -1.0), + Top: *convertFields(barcodeMap["top"], -1.0), + Percent: *convertFields(barcodeMap["percent"], -1.0), + Proportion: NewProportion(barcodeMap["proportion"]), + Center: *convertFields(barcodeMap["center"], false), + Type: NewCodeType(*convertFields(barcodeMap["type"], "")), + }, nil +} diff --git a/pkg/processor/mappers/propsmapper/barcode_test.go b/pkg/processor/mappers/propsmapper/barcode_test.go new file mode 100644 index 00000000..9426b76e --- /dev/null +++ b/pkg/processor/mappers/propsmapper/barcode_test.go @@ -0,0 +1 @@ +package propsmapper_test diff --git a/pkg/processor/mappers/propsmapper/cell.go b/pkg/processor/mappers/propsmapper/cell.go new file mode 100644 index 00000000..a27a1bb9 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/cell.go @@ -0,0 +1,41 @@ +package propsmapper + +import ( + "fmt" +) + +// Cell is the representation of a cell in the grid system. +// This can be applied to Col or Row +type Cell struct { + // BackgroundColor defines which color will be applied to a cell. + // Default: nil + BackgroundColor *Color + // BorderColor defines which color will be applied to a border cell + // Default: nil + BorderColor *Color + // BorderType defines which kind of border will be applied to a cell. + // Default: border.None + BorderType string + // BorderThickness defines the border thickness applied to a cell. + // Default: 0.2 + BorderThickness float64 + // LineStyle defines which line style will be applied to a cell. + // Default: Solid + LineStyle string +} + +// NewCell is responsible for creating the cell +func NewCell(cell interface{}) (*Cell, error) { + cellMap, ok := cell.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure cell props can be converted to map[string] interface{}") + } + + return &Cell{ + BackgroundColor: NewColor(cellMap["background_color"]), + BorderColor: NewColor(cellMap["border_color"]), + BorderType: NewBorder(*convertFields(cellMap["border_type"], "")), + BorderThickness: *convertFields(cellMap["border_thickness"], 0.0), + LineStyle: NewLineStyle(*convertFields(cellMap["line_style"], "")), + }, nil +} diff --git a/pkg/processor/mappers/propsmapper/cell_test.go b/pkg/processor/mappers/propsmapper/cell_test.go new file mode 100644 index 00000000..9426b76e --- /dev/null +++ b/pkg/processor/mappers/propsmapper/cell_test.go @@ -0,0 +1 @@ +package propsmapper_test diff --git a/pkg/processor/mappers/propsmapper/color.go b/pkg/processor/mappers/propsmapper/color.go new file mode 100644 index 00000000..4df58a86 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/color.go @@ -0,0 +1,28 @@ +package propsmapper + +// Color represents a color in the RGB (Red, Green, Blue) space, +// is possible mix values, when all values are 0 the result color is black +// when all values are 255 the result color is white. +type Color struct { + // Red is the amount of red + Red int + // Green is the amount of red + Green int + // Blue is the amount of red + Blue int +} + +// NewColor is responsible for creating the color, if the font fields cannot be +// converted, an invalid value is set. +func NewColor(color interface{}) *Color { + colorMap, ok := color.(map[string]interface{}) + if !ok { + return nil + } + + return &Color{ + Red: int(*convertFields(colorMap["red"], 0.0)), + Green: int(*convertFields(colorMap["green"], 0.0)), + Blue: int(*convertFields(colorMap["blue"], 0.0)), + } +} diff --git a/pkg/processor/mappers/propsmapper/color_test.go b/pkg/processor/mappers/propsmapper/color_test.go new file mode 100644 index 00000000..9426b76e --- /dev/null +++ b/pkg/processor/mappers/propsmapper/color_test.go @@ -0,0 +1 @@ +package propsmapper_test diff --git a/pkg/processor/mappers/propsmapper/consts.go b/pkg/processor/mappers/propsmapper/consts.go new file mode 100644 index 00000000..0f99a1ca --- /dev/null +++ b/pkg/processor/mappers/propsmapper/consts.go @@ -0,0 +1,85 @@ +package propsmapper + +func NewAlign(align string) string { + mapAligns := map[string]string{ + "left": "L", "right": "R", "center": "C", "top": "T", "bottom": "B", "middle": "M", "justify": "J", + } + align, ok := mapAligns[align] + if !ok { + return "" + } + return align +} + +func NewBorder(border string) string { + mapBorder := map[string]string{ + "full": "1", "top": "T", "bottom": "B", "left": "L", "right": "R", + } + border, ok := mapBorder[border] + if !ok { + return "" + } + return border +} + +func NewBreakLineStrategy(strategy string) string { + switch strategy { + case "empty_space_strategy": + return strategy + case "dash_strategy": + return strategy + } + return "" +} + +func NewCodeType(typeProtection string) string { + if typeProtection == "EAN" { + return "ean" + } + return "code128" +} + +func NewLineStyle(style string) string { + if style != "dashed" && style != "solid" { + return "" + } + return style +} + +func NewOrientation(orientation string) string { + switch orientation { + case "vertical": + return "vertical" + case "horizontal": + return "horizontal" + } + return "" +} + +func NewTypeProtection(typeProtection string) byte { + switch typeProtection { + case "print": + return 4 + case "modify": + return 8 + case "copy": + return 16 + case "annot_forms": + return 32 + } + + return 0 +} + +func NewFontStyle(fontType string) string { + switch fontType { + case "bold": + return "B" + case "italic": + return "I" + case "bold_italic": + return "BI" + } + + return "" +} diff --git a/pkg/processor/mappers/propsmapper/convert_fields.go b/pkg/processor/mappers/propsmapper/convert_fields.go new file mode 100644 index 00000000..1abc0a92 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/convert_fields.go @@ -0,0 +1,21 @@ +package propsmapper + +import "time" + +// convertFields is responsible for converting a value to a type. +// if it is not possible to convert, a default value is used +func convertFields[T any](val interface{}, defaultValue T) *T { + result, ok := val.(T) + if !ok { + return &defaultValue + } + return &result +} + +func factoryTime(date, layout string, defaultTime time.Time) *time.Time { + newTime, err := time.Parse(layout, date) + if err != nil { + return &defaultTime + } + return &newTime +} diff --git a/pkg/processor/mappers/propsmapper/customfont.go b/pkg/processor/mappers/propsmapper/customfont.go new file mode 100644 index 00000000..c36f5ae6 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/customfont.go @@ -0,0 +1,39 @@ +package propsmapper + +type CustomFont struct { + Family string + Style string + File string +} + +// newCustomFont is responsible for creating the CustomFont, if the CustomFont fields cannot be +// converted, an invalid value is set. +func newCustomFont(font interface{}) *CustomFont { + fontMap, ok := font.(map[string]interface{}) + if !ok { + return nil + } + + return &CustomFont{ + Family: *convertFields(fontMap["family"], ""), + Style: NewFontStyle(*convertFields(fontMap["style"], "")), + File: *convertFields(fontMap["file_path"], ""), + } +} + +// NewCustomFont is responsible for creating a CustomFont list +func NewCustomFonts(interfaceFonts interface{}) []*CustomFont { + fonts, ok := interfaceFonts.([]interface{}) + if !ok { + return nil + } + customFonts := make([]*CustomFont, 0, len(fonts)) + + for _, font := range fonts { + if newFont := newCustomFont(font); newFont != nil { + customFonts = append(customFonts, newCustomFont(font)) + } + } + + return customFonts +} diff --git a/pkg/processor/mappers/propsmapper/customfont_test.go b/pkg/processor/mappers/propsmapper/customfont_test.go new file mode 100644 index 00000000..131847e4 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/customfont_test.go @@ -0,0 +1 @@ +package propsmapper diff --git a/pkg/processor/mappers/propsmapper/dimensions.go b/pkg/processor/mappers/propsmapper/dimensions.go new file mode 100644 index 00000000..33c52b54 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/dimensions.go @@ -0,0 +1,21 @@ +package propsmapper + +// Dimensions is the representation of a width and height. +type Dimensions struct { + Width float64 + Height float64 +} + +// NewDimensions is responsible for creating the dimensions, if the font fields cannot be +// converted, an invalid value is set. +func NewDimensions(dimensions interface{}) *Dimensions { + dimensionsMap, ok := dimensions.(map[string]interface{}) + if !ok { + return nil + } + + return &Dimensions{ + Width: *convertFields(dimensionsMap["width"], -1.0), + Height: *convertFields(dimensionsMap["height"], -1.0), + } +} diff --git a/pkg/processor/mappers/propsmapper/dimensions_test.go b/pkg/processor/mappers/propsmapper/dimensions_test.go new file mode 100644 index 00000000..9426b76e --- /dev/null +++ b/pkg/processor/mappers/propsmapper/dimensions_test.go @@ -0,0 +1 @@ +package propsmapper_test diff --git a/pkg/processor/mappers/propsmapper/font.go b/pkg/processor/mappers/propsmapper/font.go new file mode 100644 index 00000000..8d34d043 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/font.go @@ -0,0 +1,43 @@ +package propsmapper + +// Font represents properties from a text. +type Font struct { + // Family of the text, ex: constf.Arial, helvetica and etc. + Family string + // Style of the text, ex: constf.Normal, bold and etc. + Style string + // Size of the text. + Size float64 + // Color define the font color. + Color *Color +} + +// NewFont is responsible for creating the fonts, if the font fields cannot be +// converted, an invalid value is set. +func NewFont(font interface{}) *Font { + fontMap, ok := font.(map[string]interface{}) + if !ok { + return nil + } + + return &Font{ + Family: *convertFields(fontMap["family"], ""), + Style: NewFontStyle(*convertFields(fontMap["style"], "")), + Size: *convertFields(fontMap["size"], 0.0), + Color: NewColor(fontMap["color"]), + } +} + +func NewListFont(fontsSource interface{}) []*Font { + listOfFonts, ok := fontsSource.([]interface{}) + if !ok { + return nil + } + fonts := make([]*Font, len(listOfFonts)) + + for i, font := range listOfFonts { + fonts[i] = NewFont(font) + } + + return fonts +} diff --git a/pkg/processor/mappers/propsmapper/font_test.go b/pkg/processor/mappers/propsmapper/font_test.go new file mode 100644 index 00000000..9426b76e --- /dev/null +++ b/pkg/processor/mappers/propsmapper/font_test.go @@ -0,0 +1 @@ +package propsmapper_test diff --git a/pkg/processor/mappers/propsmapper/line.go b/pkg/processor/mappers/propsmapper/line.go new file mode 100644 index 00000000..2e63a2ad --- /dev/null +++ b/pkg/processor/mappers/propsmapper/line.go @@ -0,0 +1,37 @@ +package propsmapper + +import "fmt" + +// Line represents properties from a Line inside a cell. +type Line struct { + // Color define the line color. + Color *Color + // Style define the line style (solid or dashed). + Style string + // Thickness define the line thicknesl. + Thickness float64 + // Orientation define if line would be horizontal or vertical. + Orientation string + // OffsetPercent define where the line would be placed, 0 is the start of cell, 50 the middle and 100 the end. + OffsetPercent float64 + // SizePercent define the size of the line inside cell. + SizePercent float64 +} + +// NewLine is responsible for creating the Line, if the font fields cannot be +// converted, an invalid value is set. +func NewLine(line interface{}) (*Line, error) { + lineMap, ok := line.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure line props can be converted to map[string] interface{}") + } + + return &Line{ + Color: NewColor(lineMap["color"]), + Style: NewLineStyle(*convertFields(lineMap["style"], "")), + Thickness: *convertFields(lineMap["thickness"], 0.0), + Orientation: NewOrientation(*convertFields(lineMap["orientation"], "")), + OffsetPercent: *convertFields(lineMap["offset_percent"], -1.0), + SizePercent: *convertFields(lineMap["size_percent"], -1.0), + }, nil +} diff --git a/pkg/processor/mappers/propsmapper/line_test.go b/pkg/processor/mappers/propsmapper/line_test.go new file mode 100644 index 00000000..9426b76e --- /dev/null +++ b/pkg/processor/mappers/propsmapper/line_test.go @@ -0,0 +1 @@ +package propsmapper_test diff --git a/pkg/processor/mappers/propsmapper/margins.go b/pkg/processor/mappers/propsmapper/margins.go new file mode 100644 index 00000000..43786ba0 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/margins.go @@ -0,0 +1,25 @@ +package propsmapper + +// Margins is the representation of a margin. +type Margins struct { + Left float64 + Right float64 + Top float64 + Bottom float64 +} + +// NewMargins is responsible for creating the margins, if the font fields cannot be +// converted, an invalid value is set. +func NewMargins(margins interface{}) *Margins { + marginsMap, ok := margins.(map[string]interface{}) + if !ok { + return nil + } + + return &Margins{ + Left: *convertFields(marginsMap["left"], -1.0), + Right: *convertFields(marginsMap["right"], -1.0), + Top: *convertFields(marginsMap["top"], -1.0), + Bottom: *convertFields(marginsMap["bottom"], -1.0), + } +} diff --git a/pkg/processor/mappers/propsmapper/margins_test.go b/pkg/processor/mappers/propsmapper/margins_test.go new file mode 100644 index 00000000..9426b76e --- /dev/null +++ b/pkg/processor/mappers/propsmapper/margins_test.go @@ -0,0 +1 @@ +package propsmapper_test diff --git a/pkg/processor/mappers/propsmapper/metadata.go b/pkg/processor/mappers/propsmapper/metadata.go new file mode 100644 index 00000000..dc5a21b8 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/metadata.go @@ -0,0 +1,53 @@ +package propsmapper + +import ( + "time" +) + +// Metadata is the representation of a PDF metadata. +type Metadata struct { + Author *Utf8Text + Creator *Utf8Text + Subject *Utf8Text + Title *Utf8Text + CreationDate *time.Time + KeywordsStr *Utf8Text +} + +// Utf8Text is the representation of a text with a flag to indicate if it's UTF8. +type Utf8Text struct { + Text string + UTF8 bool +} + +// NewUtf8Text is responsible for creating the Utf8Text, if the Utf8Text fields cannot be +// converted, an invalid value is set. +func NewUtf8Text(utf8Text interface{}) *Utf8Text { + utf8TextMap, ok := utf8Text.(map[string]interface{}) + if !ok { + return nil + } + + return &Utf8Text{ + Text: *convertFields(utf8TextMap["text"], ""), + UTF8: *convertFields(utf8TextMap["utf8"], true), + } +} + +// NewMetadata is responsible for creating the metadata, if the metadata fields cannot be +// converted, an invalid value is set. +func NewMetadata(metadata interface{}) *Metadata { + metadataMap, ok := metadata.(map[string]interface{}) + if !ok { + return nil + } + + return &Metadata{ + Author: NewUtf8Text(metadataMap["author"]), + Creator: NewUtf8Text(metadataMap["creator"]), + Subject: NewUtf8Text(metadataMap["subject"]), + Title: NewUtf8Text(metadataMap["title"]), + CreationDate: factoryTime(*convertFields(metadataMap["creation_date"], ""), "2006-01-02 15:04:05", time.Now()), + KeywordsStr: NewUtf8Text(metadataMap["keywords"]), + } +} diff --git a/pkg/processor/mappers/propsmapper/metadata_test.go b/pkg/processor/mappers/propsmapper/metadata_test.go new file mode 100644 index 00000000..9426b76e --- /dev/null +++ b/pkg/processor/mappers/propsmapper/metadata_test.go @@ -0,0 +1 @@ +package propsmapper_test diff --git a/pkg/processor/mappers/propsmapper/pagenumber.go b/pkg/processor/mappers/propsmapper/pagenumber.go new file mode 100644 index 00000000..86721ef4 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/pagenumber.go @@ -0,0 +1,35 @@ +package propsmapper + +// PageNumber have attributes of page number +type PageNumber struct { + // Pattern is the string pattern which will be used to apply the page count component. + Pattern string + // Place defines where the page count component will be placed. + Place string + // Family defines which font family will be applied to page count. + Family string + // Style defines which font style will be applied to page count. + Style string + // Size defines which font size will be applied to page count. + Size float64 + // Color defines which will be applied to page count. + Color *Color +} + +// NewPageNumber is responsible for creating the pageNumber, if the pageNumber fields cannot be +// converted, an invalid value is set. +func NewPageNumber(pageNumber interface{}) *PageNumber { + pageNumberMap, ok := pageNumber.(map[string]interface{}) + if !ok { + return nil + } + + return &PageNumber{ + Pattern: *convertFields(pageNumberMap["pattern"], ""), + Place: *convertFields(pageNumberMap["place"], ""), + Family: *convertFields(pageNumberMap["family"], ""), + Style: NewFontStyle(*convertFields(pageNumberMap["style"], "")), + Size: *convertFields(pageNumberMap["size"], 0.0), + Color: NewColor(pageNumberMap["color"]), + } +} diff --git a/pkg/processor/mappers/propsmapper/pagenumber_test.go b/pkg/processor/mappers/propsmapper/pagenumber_test.go new file mode 100644 index 00000000..9426b76e --- /dev/null +++ b/pkg/processor/mappers/propsmapper/pagenumber_test.go @@ -0,0 +1 @@ +package propsmapper_test diff --git a/pkg/processor/mappers/propsmapper/proportion.go b/pkg/processor/mappers/propsmapper/proportion.go new file mode 100644 index 00000000..dc2d976e --- /dev/null +++ b/pkg/processor/mappers/propsmapper/proportion.go @@ -0,0 +1,20 @@ +package propsmapper + +// Proportion represents a proportion from a rectangle, example: 16x9, 4x3... +type Proportion struct { + // Width from the rectangle: Barcode, image and etc. + Width float64 + // Height from the rectangle: Barcode, image and etc. + Height float64 +} + +// NewProportion is responsible for creating the proportion, if the font fields cannot be +// converted, an invalid value is set. +func NewProportion(barcode interface{}) Proportion { + barcodeMap, _ := barcode.(map[string]interface{}) + + return Proportion{ + Width: *convertFields(barcodeMap["width"], 0.0), + Height: *convertFields(barcodeMap["height"], 0.0), + } +} diff --git a/pkg/processor/mappers/propsmapper/protection.go b/pkg/processor/mappers/propsmapper/protection.go new file mode 100644 index 00000000..a9fe83f4 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/protection.go @@ -0,0 +1,23 @@ +package propsmapper + +// Protection is the representation of a pdf protection. +type Protection struct { + Type byte + UserPassword string + OwnerPassword string +} + +// NewPageNumber is responsible for creating the pageNumber, if the pageNumber fields cannot be +// converted, an invalid value is set. +func NewProtection(protection interface{}) *Protection { + protectionMap, ok := protection.(map[string]interface{}) + if !ok { + return nil + } + + return &Protection{ + Type: NewTypeProtection(*convertFields(protectionMap["type"], "None")), + UserPassword: *convertFields(protectionMap["user_password"], ""), + OwnerPassword: *convertFields(protectionMap["owner_password"], ""), + } +} diff --git a/pkg/processor/mappers/propsmapper/protection_test.go b/pkg/processor/mappers/propsmapper/protection_test.go new file mode 100644 index 00000000..9426b76e --- /dev/null +++ b/pkg/processor/mappers/propsmapper/protection_test.go @@ -0,0 +1 @@ +package propsmapper_test diff --git a/pkg/processor/mappers/propsmapper/rect.go b/pkg/processor/mappers/propsmapper/rect.go new file mode 100644 index 00000000..63206f66 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/rect.go @@ -0,0 +1,37 @@ +package propsmapper + +import "fmt" + +// Rect represents properties from a rectangle (Image, QrCode or Barcode) inside a cell. +type Rect struct { + // Left is the space between the left cell boundary to the rectangle, if center is false. + Left float64 + // Top is space between the upper cell limit to the barcode, if center is false. + Top float64 + // Percent is how much the rectangle will occupy the cell, + // ex 100%: The rectangle will fulfill the entire cell + // ex 50%: The greater side from the rectangle will have half the size of the cell. + Percent float64 + // indicate whether only the width should be used as a reference to calculate the component size, disregarding the height + // ex true: The component will be scaled only based on the available width, disregarding the available height + JustReferenceWidth bool + // Center define that the barcode will be vertically and horizontally centralized. + Center bool +} + +// NewRect is responsible for creating the Rect, if the font fields cannot be +// converted, an invalid value is set. +func NewRect(rect interface{}) (*Rect, error) { + rectMap, ok := rect.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure matrix code props can be converted to map[string] interface{}") + } + + return &Rect{ + Left: *convertFields(rectMap["left"], -1.0), + Top: *convertFields(rectMap["top"], -1.0), + Percent: *convertFields(rectMap["percent"], -1.0), + JustReferenceWidth: *convertFields(rectMap["just_reference_width"], false), + Center: *convertFields(rectMap["center"], false), + }, nil +} diff --git a/pkg/processor/mappers/propsmapper/rect_test.go b/pkg/processor/mappers/propsmapper/rect_test.go new file mode 100644 index 00000000..9426b76e --- /dev/null +++ b/pkg/processor/mappers/propsmapper/rect_test.go @@ -0,0 +1 @@ +package propsmapper_test diff --git a/pkg/processor/mappers/propsmapper/signature.go b/pkg/processor/mappers/propsmapper/signature.go new file mode 100644 index 00000000..e087dbe3 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/signature.go @@ -0,0 +1,47 @@ +package propsmapper + +import ( + "fmt" + + "github.com/johnfercher/maroto/v2/pkg/consts/linestyle" +) + +// Signature represents properties from a signature. +type Signature struct { + // FontFamily of the text, ex: consts.Arial, helvetica and etc. + FontFamily string + // FontStyle of the text, ex: consts.Normal, bold and etc. + FontStyle string + // FontSize of the text. + FontSize float64 + // FontColor define the font color. + FontColor *Color + // LineColor define the line color. + LineColor *Color + // LineStyle define the line style (solid or dashed). + LineStyle linestyle.Type + // LineThickness define the line thickness. + LineThickness float64 + + SafePadding float64 +} + +// NewSignature is responsible for creating the Signature, if the font fields cannot be +// converted, an invalid value is set. +func NewSignature(signature interface{}) (*Signature, error) { + signatureMap, ok := signature.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure barcode props can be converted to map[string] interface{}") + } + + return &Signature{ + FontFamily: *convertFields(signatureMap["font_family"], ""), + FontStyle: NewFontStyle(*convertFields(signatureMap["font_style"], "")), + FontSize: *convertFields(signatureMap["font_size"], 0.0), + FontColor: NewColor(signatureMap["font_color"]), + LineColor: NewColor(signatureMap["line_color"]), + LineStyle: linestyle.Type(NewLineStyle(*convertFields(signatureMap["line_style"], ""))), + LineThickness: *convertFields(signatureMap["line_thickness"], 0.0), + SafePadding: *convertFields(signatureMap["safe_padding"], -1.0), + }, nil +} diff --git a/pkg/processor/mappers/propsmapper/signature_test.go b/pkg/processor/mappers/propsmapper/signature_test.go new file mode 100644 index 00000000..9426b76e --- /dev/null +++ b/pkg/processor/mappers/propsmapper/signature_test.go @@ -0,0 +1 @@ +package propsmapper_test diff --git a/pkg/processor/mappers/propsmapper/text.go b/pkg/processor/mappers/propsmapper/text.go new file mode 100644 index 00000000..8e13a779 --- /dev/null +++ b/pkg/processor/mappers/propsmapper/text.go @@ -0,0 +1,59 @@ +package propsmapper + +import ( + "fmt" +) + +// Text represents properties from a Text inside a cell. +type Text struct { + // Top is the amount of space between the upper cell limit and the text. + Top float64 + // Bottom is the amount of space between the lower cell limit and the text. (Used by auto row only) + Bottom float64 + // Left is the minimal amount of space between the left cell boundary and the text. + Left float64 + // Right is the minimal amount of space between the right cell boundary and the text. + Right float64 + // Family of the text, ex: consts.Arial, helvetica and etc. + Family string + // Style of the text, ex: consts.Normal, bold and etc. + Style string + // Size of the text. + Size float64 + // Align of the text. + Align string + // BreakLineStrategy define the break line strategy. + BreakLineStrategy string + // VerticalPadding define an additional space between linet. + VerticalPadding float64 + // Color define the font style color. + Color *Color + // Hyperlink define a link to be opened when the text is clicked. + Hyperlink *string +} + +// NewText is responsible for creating the Text, if the font fields cannot be +// converted, an invalid value is set. +func NewText(signature interface{}) (*Text, error) { + signatureMap, ok := signature.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("ensure text props can be converted to map[string] interface{}") + } + text := &Text{ + Top: *convertFields(signatureMap["top"], -1.0), + Left: *convertFields(signatureMap["left"], -1.0), + Right: *convertFields(signatureMap["right"], -1.0), + Bottom: *convertFields(signatureMap["bottom"], -1.0), + Family: *convertFields(signatureMap["family"], ""), + Style: NewFontStyle(*convertFields(signatureMap["style"], "")), + Size: *convertFields(signatureMap["size"], 0.0), + Align: NewAlign(*convertFields(signatureMap["align"], "")), + BreakLineStrategy: NewBreakLineStrategy(*convertFields(signatureMap["break_line_strategy"], "")), + VerticalPadding: *convertFields(signatureMap["vertical_padding"], -1.0), + Color: NewColor(signatureMap["color"]), + } + if hyperlink := *convertFields(signatureMap["hyperlink"], ""); hyperlink != "" { + text.Hyperlink = &hyperlink + } + return text, nil +} diff --git a/pkg/processor/mappers/propsmapper/text_test.go b/pkg/processor/mappers/propsmapper/text_test.go new file mode 100644 index 00000000..9426b76e --- /dev/null +++ b/pkg/processor/mappers/propsmapper/text_test.go @@ -0,0 +1 @@ +package propsmapper_test diff --git a/pkg/processor/processor.go b/pkg/processor/processor.go new file mode 100644 index 00000000..1d5d9466 --- /dev/null +++ b/pkg/processor/processor.go @@ -0,0 +1,63 @@ +package processor + +import ( + "github.com/johnfercher/maroto/v2/pkg/processor/core" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/abstractfactory" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/documentmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" +) + +type processor struct { + repository core.ProcessorRepository + deserializer core.Deserializer +} + +// NewProcessor is responsible for creating a processor object +// The processor object should be used to create PDF from a serialized document +func NewProcessor(repository core.ProcessorRepository, deserializer core.Deserializer) *processor { + return &processor{ + repository: repository, + deserializer: deserializer, + } +} + +// RegisterTemplate is responsible for recording the document template. +// Each template must be accompanied by a name that will identify it. +func (p *processor) RegisterTemplate(templateName string, template string) error { + t, err := p.deserializer.Deserialize(template) + if err != nil { + return err + } + return p.repository.RegisterTemplate(templateName, t) +} + +// GenerateDocument is responsible for generating the pdf +// templateName must reference a previously saved template, +// this template will be computed with the data sent in content +func (p *processor) GenerateDocument(templateName string, content string) (*processorprovider.ProcessorProvider, error) { + template, err := p.repository.ReadTemplate(templateName) + if err != nil { + return nil, err + } + + document, err := documentmapper.NewPdf(template, abstractfactory.NewAbstractFactoryMaps(p.repository)) + if err != nil { + return nil, err + } + + marotoProvider, err := processorprovider.NewMaroto(p.repository, *document.GetBuilderCfg()) + if err != nil { + return nil, err + } + + contentMap, err := p.deserializer.Deserialize(content) + if err != nil { + return nil, err + } + + provider, err := (*document).Generate(contentMap, marotoProvider) + if err != nil { + return nil, err + } + return provider, nil +} diff --git a/pkg/processor/processor_test.go b/pkg/processor/processor_test.go new file mode 100644 index 00000000..b52bd8cd --- /dev/null +++ b/pkg/processor/processor_test.go @@ -0,0 +1,420 @@ +package processor_test + +import ( + "testing" + + "github.com/johnfercher/maroto/v2/pkg/processor" + "github.com/johnfercher/maroto/v2/pkg/processor/deserializer" + "github.com/johnfercher/maroto/v2/pkg/processor/loader" + "github.com/johnfercher/maroto/v2/pkg/processor/repository" + processortest "github.com/johnfercher/maroto/v2/pkg/processor/test" + "github.com/johnfercher/maroto/v2/pkg/test" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestRegisterTemplate(t *testing.T) { + t.Run("when template is recorded, should no return error", func(t *testing.T) { + }) + t.Run("when is not possible deserialize template, should return an error", func(t *testing.T) { + }) + t.Run("when is not possible register template, should return an error", func(t *testing.T) { + }) +} + +func TestGenerateTemplate(t *testing.T) { + t.Run("when valid template is found, should return valid pdf", func(t *testing.T) { + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/simple_pdf_templates.json") + fixContent, _ := processortest.NewFileReader().LoadFile("processor/json/simple_pdf_content.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("simple_pdf", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("simple_pdf", string(fixContent)) + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("processor/simple_pdf.json") + }) + + t.Run("when template with Addpage example is found, should set template", func(t *testing.T) { + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/add_page_template.json") + fixContent, _ := processortest.NewFileReader().LoadFile("processor/json/add_page_content.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("add_page", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("add_page", string(fixContent)) + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/addpage.json") + }) + + t.Run("when template with AutoRow example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/auto_row_template.json") + fixContent, _ := processortest.NewFileReader().LoadFile("processor/json/auto_row_content.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("auto_row", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("auto_row", string(fixContent)) + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/autorow.json") + }) + t.Run("when template with background example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/background_template.json") + fixContent, _ := processortest.NewFileReader().LoadFile("processor/json/background_content.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("background", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("background", string(fixContent)) + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/background.json") + }) + t.Run("when template with barcodegrid example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/barcodegrid_template.json") + fixContent, _ := processortest.NewFileReader().LoadFile("processor/json/barcodegrid_content.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("barcodegrid", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("barcodegrid", string(fixContent)) + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/barcodegrid.json") + }) + t.Run("when template with billing example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/billing_template.json") + fixContent, _ := processortest.NewFileReader().LoadFile("processor/json/billing_content.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("billing", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("billing", string(fixContent)) + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/billing.json") + }) + t.Run("when template with cellstyle example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/cell_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("cellstyle", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("cellstyle", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/cellstyle.json") + }) + t.Run("when template with compression example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/compressionv2_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("compression", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("compression", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/compression.json") + }) + t.Run("when template with customdimensions example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/customdimensions_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("dimensions", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("dimensions", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/customdimensions.json") + }) + t.Run("when template with customfont example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/customfont_template.json") + fixcontent, _ := processortest.NewFileReader().LoadFile("processor/json/customfont_content.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("font", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("font", string(fixcontent)) + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/customfont.json") + }) + t.Run("when template with custompage example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/custompage_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("page", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("page", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/custompage.json") + }) + t.Run("when template with datamatrixgrid example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/datamatrixgrid_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("datamatrixgrid", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("datamatrixgrid", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/datamatrixgrid.json") + }) + t.Run("when template with autopagebreak example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/disablepagebreak_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("disablepagebreak", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("disablepagebreak", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/disablepagebreak.json") + }) + t.Run("when template with footer example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/footer_template.json") + fixcontent, _ := processortest.NewFileReader().LoadFile("processor/json/footer_content.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("footer", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("footer", string(fixcontent)) + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/footer.json") + }) + t.Run("when template with header example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/header_template.json") + fixcontent, _ := processortest.NewFileReader().LoadFile("processor/json/header_content.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("header", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("header", string(fixcontent)) + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/header.json") + }) + t.Run("when template with imagegrid example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/imagegrid_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("imagegrid", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("imagegrid", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/imagegrid.json") + }) + t.Run("when template with linegrid example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/linegrid_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("line", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("line", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/line.json") + }) + t.Run("when template with lowmemory example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/lowmemory_template.json") + fixcontent, _ := processortest.NewFileReader().LoadFile("processor/json/lowmemory_content.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("lowmemory", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("lowmemory", string(fixcontent)) + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/lowmemory.json") + }) + t.Run("when template with margins example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/margins_template.json") + fixcontent, _ := processortest.NewFileReader().LoadFile("processor/json/margins_content.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("margins", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("margins", string(fixcontent)) + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/margins.json") + }) + t.Run("when template with maxgridsum example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/maxgridsum_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("margins", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("margins", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/maxgridsum.json") + }) + t.Run("when template with metadata example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/metadata_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("metadata", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("metadata", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/metadatas.json") + }) + t.Run("when template with orientation example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/orientation_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("orientation", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("orientation", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/orientation.json") + }) + t.Run("when template with pagenumber example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/pagenumber_template.json") + fixcontent, _ := processortest.NewFileReader().LoadFile("processor/json/pagenumber_content.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("orientation", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("orientation", string(fixcontent)) + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/pagenumber.json") + }) + t.Run("when template with parallelism example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/parallelism_template.json") + fixcontent, _ := processortest.NewFileReader().LoadFile("processor/json/parallelism_content.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("parallelism", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("parallelism", string(fixcontent)) + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/parallelism.json") + }) + t.Run("when template with protection example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/protection_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("protection", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("protection", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/protection.json") + }) + t.Run("when template with qrcodegrid example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/qrcodegrid_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("qrcodegrid", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("qrcodegrid", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/qrgrid.json") + }) + t.Run("when template with signature example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/signature_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("signature", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("signature", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/signaturegrid.json") + }) + + t.Run("when template with simplest example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/simplest_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("simplest", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("simplest", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/simplest.json") + }) + t.Run("when template with textgrid example is found, should set template", func(t *testing.T) { + test.SetupTestDir(t) + + fixtemplate, _ := processortest.NewFileReader().LoadFile("processor/json/textgrid_template.json") + processor := processor.NewProcessor(repository.NewMemoryStorage(loader.NewLoader()), deserializer.NewJSONDeserializer()) + err := processor.RegisterTemplate("textgrid", string(fixtemplate)) + require.NoError(t, err) + + provider, err := processor.GenerateDocument("textgrid", "{}") + + assert.Nil(t, err) + test.New(t).Assert((*provider).GetStructure()).Equals("examples/textgrid.json") + }) + + t.Run("when template with invalid field is found, should return an error", func(t *testing.T) { + }) + t.Run("when invalid content is sent, should return an error", func(t *testing.T) { + }) +} diff --git a/pkg/processor/processorprovider/Maroto.go b/pkg/processor/processorprovider/Maroto.go new file mode 100644 index 00000000..40beb80e --- /dev/null +++ b/pkg/processor/processorprovider/Maroto.go @@ -0,0 +1,276 @@ +package processorprovider + +import ( + "fmt" + "net/url" + "strings" + + "github.com/johnfercher/go-tree/node" + "github.com/johnfercher/maroto/v2" + "github.com/johnfercher/maroto/v2/pkg/components/code" + "github.com/johnfercher/maroto/v2/pkg/components/col" + "github.com/johnfercher/maroto/v2/pkg/components/image" + "github.com/johnfercher/maroto/v2/pkg/components/line" + "github.com/johnfercher/maroto/v2/pkg/components/page" + "github.com/johnfercher/maroto/v2/pkg/components/row" + "github.com/johnfercher/maroto/v2/pkg/components/signature" + "github.com/johnfercher/maroto/v2/pkg/components/text" + "github.com/johnfercher/maroto/v2/pkg/config" + "github.com/johnfercher/maroto/v2/pkg/consts/align" + "github.com/johnfercher/maroto/v2/pkg/consts/barcode" + "github.com/johnfercher/maroto/v2/pkg/consts/border" + "github.com/johnfercher/maroto/v2/pkg/consts/breakline" + "github.com/johnfercher/maroto/v2/pkg/consts/extension" + "github.com/johnfercher/maroto/v2/pkg/consts/fontstyle" + "github.com/johnfercher/maroto/v2/pkg/consts/linestyle" + "github.com/johnfercher/maroto/v2/pkg/consts/orientation" + "github.com/johnfercher/maroto/v2/pkg/core" + processorcore "github.com/johnfercher/maroto/v2/pkg/processor/core" + "github.com/johnfercher/maroto/v2/pkg/processor/loader" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/buildermapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/props" +) + +type Maroto struct { + maroto core.Maroto + repository processorcore.ProcessorRepository +} + +func NewMaroto(repository processorcore.ProcessorRepository, builder ...buildermapper.Builder) (ProcessorProvider, error) { + cfg := config.NewBuilder() + + if len(builder) > 0 { + var err error + cfg, err = NewMarotoBuilder(repository, config.NewBuilder()).CreateMarotoBuilder(&builder[0]) + if err != nil { + return nil, err + } + } + m := maroto.New(cfg.Build()) + return &Maroto{maroto: m, repository: repository}, nil +} + +func (m *Maroto) Generate() (core.Document, error) { + return m.maroto.Generate() +} + +func (m *Maroto) GetStructure() *node.Node[core.Structure] { + return m.maroto.GetStructure() +} + +func (m *Maroto) AddPages(pages ...ProviderComponent) (ProcessorProvider, error) { + if len(pages) == 0 { + return m, nil + } + newPages, err := convertComponentType[core.Page](pages...) + if err != nil { + return nil, err + } + + m.maroto.AddPages(newPages...) + return m, nil +} + +func (m *Maroto) AddFooter(footer ...ProviderComponent) (ProcessorProvider, error) { + if len(footer) == 0 { + return m, nil + } + newFooter, err := convertComponentType[core.Row](footer...) + if err != nil { + return nil, err + } + + err = m.maroto.RegisterFooter(newFooter...) + if err != nil { + return nil, err + } + return m, nil +} + +func (m *Maroto) AddHeader(header ...ProviderComponent) (ProcessorProvider, error) { + if len(header) == 0 { + return m, nil + } + newHeader, err := convertComponentType[core.Row](header...) + if err != nil { + return nil, err + } + + err = m.maroto.RegisterHeader(newHeader...) + if err != nil { + return nil, err + } + return m, nil +} + +func (m *Maroto) CreatePage(components ...ProviderComponent) (ProviderComponent, error) { + newComponents, err := convertComponentType[core.Row](components...) + if err != nil { + return nil, err + } + + return page.New().Add(newComponents...), nil +} + +func (m *Maroto) CreateRow(height float64, props *propsmapper.Cell, components ...ProviderComponent) (ProviderComponent, error) { + newComponents, err := convertComponentType[core.Col](components...) + if err != nil { + return nil, err + } + + var createdRow core.Row + if height > 0 { + createdRow = row.New(height).Add(newComponents...) + } else { + createdRow = row.New().Add(newComponents...) + } + + if props != nil { + return createdRow.WithStyle(createPropsCell(*props)), nil + } else { + return createdRow, nil + } +} + +func (m *Maroto) CreateCol(size int, props *propsmapper.Cell, components ...ProviderComponent) (ProviderComponent, error) { + newComponents, err := convertComponentType[core.Component](components...) + if err != nil { + return nil, err + } + + var createdCol core.Col + if size > 0 { + createdCol = col.New(size).Add(newComponents...) + } else { + createdCol = col.New().Add(newComponents...) + } + + if props != nil { + return createdCol.WithStyle(createPropsCell(*props)), nil + } else { + return createdCol, nil + } +} + +func (m *Maroto) CreateText(value string, textsProps ...*propsmapper.Text) ProviderComponent { + tProps := propsmapper.Text{} + if len(textsProps) > 0 { + tProps = *textsProps[0] + } + + return text.New(value, props.Text{ + Top: tProps.Top, Bottom: tProps.Bottom, Left: tProps.Left, Right: tProps.Right, Family: tProps.Family, + Style: fontstyle.Type(tProps.Style), Size: tProps.Size, Align: align.Type(tProps.Align), + BreakLineStrategy: breakline.Strategy(tProps.BreakLineStrategy), VerticalPadding: tProps.VerticalPadding, + Color: (*props.Color)(tProps.Color), Hyperlink: tProps.Hyperlink, + }) +} + +func (m *Maroto) CreateSignature(value string, signaturesProps ...*propsmapper.Signature) ProviderComponent { + sProps := propsmapper.Signature{} + if len(signaturesProps) > 0 { + sProps = *signaturesProps[0] + } + + return signature.New(value, props.Signature{ + FontFamily: sProps.FontFamily, FontStyle: fontstyle.Type(sProps.FontStyle), FontSize: sProps.FontSize, + FontColor: (*props.Color)(sProps.FontColor), LineColor: (*props.Color)(sProps.LineColor), LineStyle: sProps.LineStyle, + LineThickness: sProps.LineThickness, SafePadding: sProps.SafePadding, + }) +} + +func (m *Maroto) CreateLine(lineProps ...*propsmapper.Line) ProviderComponent { + lProps := propsmapper.Line{} + if len(lineProps) > 0 { + lProps = *lineProps[0] + } + + return line.New(props.Line{ + Color: (*props.Color)(lProps.Color), Style: linestyle.Type(lProps.Style), Thickness: lProps.Thickness, + Orientation: orientation.Type(lProps.Orientation), OffsetPercent: lProps.OffsetPercent, SizePercent: lProps.SizePercent, + }) +} + +func (m *Maroto) CreateImageWithLocalePath(uri *url.URL, props ...props.Rect) (ProviderComponent, error) { + newPath := strings.TrimPrefix(uri.String(), "file://") + return image.NewFromFile(newPath, props...), nil +} + +func (m *Maroto) CreateImageWithExternalPath(path *url.URL, props ...props.Rect) (ProviderComponent, error) { + ext, img, err := m.repository.GetDocument(path.String()) + if err != nil { + return nil, err + } + return image.NewFromBytes(img, extension.Type(ext), props...), nil +} + +func (m *Maroto) CreateImage(path string, propsMapperArr ...*propsmapper.Rect) (ProviderComponent, error) { + props := createPropsRect(propsMapperArr...) + uri, err := loader.GetResourceSource(path) + if err != nil { + return nil, err + } + + if uri.Scheme == "file" { + return m.CreateImageWithLocalePath(uri, props) + } else { + return m.CreateImageWithExternalPath(uri, props) + } +} + +func (m *Maroto) CreateMatrixCode(codeValue string, codeProps ...*propsmapper.Rect) ProviderComponent { + props := createPropsRect(codeProps...) + return code.NewMatrix(codeValue, props) +} + +func (m *Maroto) CreateQrCode(codeValue string, codeProps ...*propsmapper.Rect) ProviderComponent { + props := createPropsRect(codeProps...) + return code.NewQr(codeValue, props) +} + +func (m *Maroto) CreateBarCode(codeValue string, codeProps ...*propsmapper.Barcode) ProviderComponent { + cProps := propsmapper.Barcode{} + if len(codeProps) > 0 { + cProps = *codeProps[0] + } + + return code.NewBar(codeValue, props.Barcode{ + Left: cProps.Left, Top: cProps.Top, Percent: cProps.Percent, + Proportion: props.Proportion(cProps.Proportion), Center: cProps.Center, Type: barcode.Type(cProps.Type), + }) +} + +func convertComponentType[T any](components ...ProviderComponent) ([]T, error) { + newComponents := make([]T, len(components)) + for i, component := range components { + validComponent, ok := component.(T) + if !ok { + return nil, fmt.Errorf("could not convert pdf components to a valid type") + } + newComponents[i] = validComponent + } + return newComponents, nil +} + +func createPropsRect(propsMapperArr ...*propsmapper.Rect) props.Rect { + propsRect := props.Rect{} + if len(propsMapperArr) > 0 { + propsMapper := *propsMapperArr[0] + propsRect = props.Rect{ + Left: propsMapper.Left, Top: propsMapper.Top, Percent: propsMapper.Percent, + JustReferenceWidth: propsMapper.JustReferenceWidth, Center: propsMapper.Center, + } + } + return propsRect +} + +func createPropsCell(propsCell propsmapper.Cell) *props.Cell { + return &props.Cell{ + BackgroundColor: (*props.Color)(propsCell.BackgroundColor), + BorderColor: (*props.Color)(propsCell.BorderColor), + BorderType: border.Type(propsCell.BorderType), + BorderThickness: propsCell.BorderThickness, + LineStyle: linestyle.Type(propsCell.LineStyle), + } +} diff --git a/pkg/processor/processorprovider/Maroto_test.go b/pkg/processor/processorprovider/Maroto_test.go new file mode 100644 index 00000000..1ebf8546 --- /dev/null +++ b/pkg/processor/processorprovider/Maroto_test.go @@ -0,0 +1,314 @@ +package processorprovider_test + +import ( + "fmt" + "testing" + + "github.com/johnfercher/maroto/v2/mocks" + "github.com/johnfercher/maroto/v2/pkg/components/code" + "github.com/johnfercher/maroto/v2/pkg/components/page" + "github.com/johnfercher/maroto/v2/pkg/components/row" + "github.com/johnfercher/maroto/v2/pkg/components/text" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/buildermapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" + "github.com/johnfercher/maroto/v2/pkg/processor/repository" + "github.com/johnfercher/maroto/v2/pkg/test" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func TestAddPages(t *testing.T) { + t.Run("when page is not sent, should not add header", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + provider, _ := processorprovider.NewMaroto(repository) + + provider, err := provider.AddPages() + + assert.Nil(t, err) + assert.NotNil(t, provider) + }) + + t.Run("when invalid component is sent, should return an error", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + provider, _ := processorprovider.NewMaroto(repository) + + provider, err := provider.AddPages(text.New("123")) + + assert.NotNil(t, err) + assert.Nil(t, provider) + }) + + t.Run("when page is sent, should add page", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + provider, _ := processorprovider.NewMaroto(repository) + + provider, err := provider.AddPages(page.New().Add(row.New(10))) + + assert.NotNil(t, provider) + assert.Nil(t, err) + test.New(t).Assert(provider.GetStructure()).Equals("processor/provider/document_with_page.json") + }) +} + +// nolint: dupl +func TestAddFooter(t *testing.T) { + t.Run("when footer is not sent, should not add footer", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + provider, _ := processorprovider.NewMaroto(repository) + + provider, err := provider.AddFooter() + + assert.Nil(t, err) + assert.NotNil(t, provider) + }) + + t.Run("when invalid component is sent, should return an error", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + provider, _ := processorprovider.NewMaroto(repository) + + provider, err := provider.AddFooter(page.New()) + + assert.NotNil(t, err) + assert.Nil(t, provider) + }) + + t.Run("when footer is sent, should add footer", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + provider, _ := processorprovider.NewMaroto(repository) + + provider, err := provider.AddFooter(text.NewAutoRow("footer")) + + assert.NotNil(t, provider) + assert.Nil(t, err) + test.New(t).Assert(provider.GetStructure()).Equals("processor/provider/document_with_footer.json") + }) +} + +// nolint: dupl +func TestAddHeader(t *testing.T) { + t.Run("when header is not sent, should not add header", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + provider, _ := processorprovider.NewMaroto(repository) + + provider, err := provider.AddHeader() + + assert.Nil(t, err) + assert.NotNil(t, provider) + }) + + t.Run("when invalid component is sent, should return an error", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + provider, _ := processorprovider.NewMaroto(repository) + + provider, err := provider.AddHeader(page.New()) + + assert.NotNil(t, err) + assert.Nil(t, provider) + }) + + t.Run("when header is sent, should add header", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + provider, _ := processorprovider.NewMaroto(repository) + + provider, err := provider.AddHeader(text.NewAutoRow("header")) + + assert.NotNil(t, provider) + assert.Nil(t, err) + test.New(t).Assert(provider.GetStructure()).Equals("processor/provider/document_with_header.json") + }) +} + +func TestNewMaroto(t *testing.T) { + t.Run("when builder is not sent, should not create Maroto builder", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + + provider, err := processorprovider.NewMaroto(repository) + + assert.NotNil(t, provider) + assert.Nil(t, err) + }) + t.Run("when is not possible create Maroto builder, should return an error", func(t *testing.T) { + mapperFix := buildermapper.Builder{BackgroundImage: "file"} + repository := mocks.NewProcessorRepository(t) + repository.EXPECT().GetDocument(mock.Anything).Return("", nil, fmt.Errorf("any")) + + provider, err := processorprovider.NewMaroto(repository, mapperFix) + + assert.NotNil(t, err) + assert.Nil(t, provider) + }) + t.Run("when builder is sent, should create Maroto builder", func(t *testing.T) { + mapperFix := buildermapper.Builder{BackgroundImage: "file"} + repository := mocks.NewProcessorRepository(t) + repository.EXPECT().GetDocument(mock.Anything).Return("", []byte{123}, nil) + + provider, err := processorprovider.NewMaroto(repository, mapperFix) + + assert.NotNil(t, provider) + assert.Nil(t, err) + }) +} + +func TestCreateBarCode(t *testing.T) { + t.Run("when CreateBarCode is called, should generate a barcode", func(t *testing.T) { + loader := mocks.NewLoader(t) + m, _ := processorprovider.NewMaroto(repository.NewMemoryStorage(loader)) + barcode := m.CreateBarCode("code", + &propsmapper.Barcode{ + Left: 10.0, Top: 10.0, Percent: 100.0, + Proportion: propsmapper.Proportion{Width: 10, Height: 2}, + Center: false, Type: propsmapper.NewCodeType("code128"), + }, + ) + + assert.IsType(t, barcode, &code.Barcode{}) + test.New(t).Assert(barcode.GetStructure()).Equals("processor/provider/barcode.json") + }) +} + +func TestCreateMatrixCode(t *testing.T) { + t.Run("when CreateMatrixCode is called, should generate a matrixcode", func(t *testing.T) { + loader := mocks.NewLoader(t) + m, _ := processorprovider.NewMaroto(repository.NewMemoryStorage(loader)) + barcode := m.CreateMatrixCode("code", + &propsmapper.Rect{Left: 10.0, Top: 10.0, Percent: 100.0, JustReferenceWidth: false, Center: false}, + ) + + test.New(t).Assert(barcode.GetStructure()).Equals("processor/provider/matrixcode.json") + }) +} + +func TestCreateQRCode(t *testing.T) { + t.Run("when CreateQrCode is called, should generate a qrcode", func(t *testing.T) { + loader := mocks.NewLoader(t) + m, _ := processorprovider.NewMaroto(repository.NewMemoryStorage(loader)) + barcode := m.CreateQrCode("code", + &propsmapper.Rect{Left: 10.0, Top: 10.0, Percent: 100.0, JustReferenceWidth: false, Center: false}, + ) + + test.New(t).Assert(barcode.GetStructure()).Equals("processor/provider/qrcode.json") + }) +} + +func TestCreateImage(t *testing.T) { + t.Run("when CreateImage is called, should generate a image", func(t *testing.T) { + loader := mocks.NewLoader(t) + m, _ := processorprovider.NewMaroto(repository.NewMemoryStorage(loader)) + image, err := m.CreateImage("img.png", + &propsmapper.Rect{Left: 10.0, Top: 10.0, Percent: 100.0, JustReferenceWidth: false, Center: false}, + ) + + assert.Nil(t, err) + test.New(t).Assert(image.GetStructure()).Equals("processor/provider/image.json") + }) +} + +func TestCreateLine(t *testing.T) { + t.Run("when CreateLine is called, should generate a line", func(t *testing.T) { + loader := mocks.NewLoader(t) + m, _ := processorprovider.NewMaroto(repository.NewMemoryStorage(loader)) + barcode := m.CreateLine( + &propsmapper.Line{ + Color: &propsmapper.Color{Red: 10, Green: 10, Blue: 10}, Style: "solid", Thickness: 10.0, + Orientation: "vertical", OffsetPercent: 50, SizePercent: 50, + }, + ) + + test.New(t).Assert(barcode.GetStructure()).Equals("processor/provider/line.json") + }) +} + +func TestCreateSignature(t *testing.T) { + t.Run("when CreateSignature is called, should generate a signature", func(t *testing.T) { + loader := mocks.NewLoader(t) + m, _ := processorprovider.NewMaroto(repository.NewMemoryStorage(loader)) + barcode := m.CreateSignature("signature", + &propsmapper.Signature{ + FontFamily: "Arial", FontStyle: "bold", FontSize: 10.0, FontColor: &propsmapper.Color{Red: 10, Green: 10, Blue: 10}, + LineColor: &propsmapper.Color{Red: 10, Green: 10, Blue: 10}, LineStyle: "solid", LineThickness: 10.0, SafePadding: 10.0, + }, + ) + + test.New(t).Assert(barcode.GetStructure()).Equals("processor/provider/signature.json") + }) +} + +func TestCreateText(t *testing.T) { + t.Run("when CreateText is called, should generate a text", func(t *testing.T) { + hyperlink := "test" + loader := mocks.NewLoader(t) + m, _ := processorprovider.NewMaroto(repository.NewMemoryStorage(loader)) + barcode := m.CreateText("text", + &propsmapper.Text{ + Top: 10.0, Left: 10.0, Right: 10.0, Family: "Arial", Style: "bold", Size: 10.0, Align: "center", BreakLineStrategy: "dash_strategy", + VerticalPadding: 10.0, Color: &propsmapper.Color{Red: 10, Green: 10, Blue: 10}, Hyperlink: &hyperlink, + }, + ) + + test.New(t).Assert(barcode.GetStructure()).Equals("processor/provider/text.json") + }) +} + +func TestCreateCol(t *testing.T) { + t.Run("when CreateCol is called, should generate a col", func(t *testing.T) { + loader := mocks.NewLoader(t) + m, _ := processorprovider.NewMaroto(repository.NewMemoryStorage(loader)) + text := text.New("test") + + col, err := m.CreateCol(10, (*propsmapper.Cell)(nil), text) + + assert.Nil(t, err) + assert.NotNil(t, col) + }) + + t.Run("when invalid components are sent, should return an error", func(t *testing.T) { + loader := mocks.NewLoader(t) + m, _ := processorprovider.NewMaroto(repository.NewMemoryStorage(loader)) + page, err := m.CreatePage(text.NewCol(10, "10")) + + assert.Nil(t, page) + assert.NotNil(t, err) + }) +} + +func TestCreateRow(t *testing.T) { + t.Run("when CreateRow is called, should generate a row", func(t *testing.T) { + loader := mocks.NewLoader(t) + m, _ := processorprovider.NewMaroto(repository.NewMemoryStorage(loader)) + text := text.NewCol(12, "test") + + col, err := m.CreateRow(10, (*propsmapper.Cell)(nil), text) + + assert.Nil(t, err) + assert.NotNil(t, col) + }) + + t.Run("when invalid components are sent, should return an error", func(t *testing.T) { + loader := mocks.NewLoader(t) + m, _ := processorprovider.NewMaroto(repository.NewMemoryStorage(loader)) + page, err := m.CreatePage(text.New("10")) + + assert.Nil(t, page) + assert.NotNil(t, err) + }) +} + +func TestCreatePage(t *testing.T) { + t.Run("when CreatePage is called, should generate a page", func(t *testing.T) { + loader := mocks.NewLoader(t) + m, _ := processorprovider.NewMaroto(repository.NewMemoryStorage(loader)) + page, err := m.CreatePage(row.New(10)) + + assert.Nil(t, err) + assert.NotNil(t, page) + }) + t.Run("when invalid components are sent, should return an error", func(t *testing.T) { + loader := mocks.NewLoader(t) + m, _ := processorprovider.NewMaroto(repository.NewMemoryStorage(loader)) + page, err := m.CreatePage(text.New("10")) + + assert.Nil(t, page) + assert.NotNil(t, err) + }) +} diff --git a/pkg/processor/processorprovider/builder_maroto.go b/pkg/processor/processorprovider/builder_maroto.go new file mode 100644 index 00000000..3c15fe04 --- /dev/null +++ b/pkg/processor/processorprovider/builder_maroto.go @@ -0,0 +1,226 @@ +package processorprovider + +import ( + "github.com/johnfercher/maroto/v2/pkg/config" + "github.com/johnfercher/maroto/v2/pkg/consts/extension" + "github.com/johnfercher/maroto/v2/pkg/consts/fontstyle" + "github.com/johnfercher/maroto/v2/pkg/consts/orientation" + "github.com/johnfercher/maroto/v2/pkg/consts/pagesize" + "github.com/johnfercher/maroto/v2/pkg/consts/protection" + "github.com/johnfercher/maroto/v2/pkg/core/entity" + "github.com/johnfercher/maroto/v2/pkg/processor/core" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/buildermapper" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/props" + "github.com/johnfercher/maroto/v2/pkg/repository" +) + +// MarotoBuilder is responsible for creating Maroto builder props from buildermapper +type MarotoBuilder struct { + cfg config.Builder + repository core.ProcessorRepository +} + +// NewMarotoBuilder is responsible for creating an object MarotoBuilder +// - It will use repository for search files like image and font +func NewMarotoBuilder(repository core.ProcessorRepository, cfg config.Builder) *MarotoBuilder { + return &MarotoBuilder{ + repository: repository, + cfg: cfg, + } +} + +// CreateMarotoBuilder is responsible for facilitating the creation of the builder +func (m *MarotoBuilder) CreateMarotoBuilder(builder *buildermapper.Builder) (config.Builder, error) { + m = m.WithPageSize(builder.PageSize).WithDimensions(builder.Dimensions).WithMargin(builder.Margins). + WithConcurrentMode(builder.ConcurrentMode).WithSequentialMode(builder.SequentialMode). + WithSequentialLowMemoryMode(builder.SequentialLowMemoryMode).WithDebug(builder.Debug).WithMaxGridSize(builder.MaxGridSize). + WithDefaultFont(builder.DefaultFont).WithPageNumber(builder.PageNumber).WithProtection(builder.Protection). + WithCompression(builder.Compression).WithOrientation(builder.Orientation).WithMetadata(builder.Metadata). + WithDisableAutoPageBreak(builder.DisableAutoPageBreak) + + if _, err := m.WithBackgroundImage(builder.BackgroundImage); err != nil { + return nil, err + } + if _, err := m.WithCustomFonts(builder.CustomFonts); err != nil { + return nil, err + } + + return m.cfg, nil +} + +// WithPageSize will add page size properties +// - if size is null, size will not be added +func (m *MarotoBuilder) WithPageSize(size string) *MarotoBuilder { + validAndRun(func() { m.cfg.WithPageSize(pagesize.Type(size)) }, size != "") + return m +} + +// WithDimensions defines custom page dimensions, this overrides page size. +// - if dimensions is null, dimensions will not be added +func (m *MarotoBuilder) WithDimensions(dimensions *propsmapper.Dimensions) *MarotoBuilder { + validAndRun(func() { m.cfg.WithDimensions(dimensions.Width, dimensions.Height) }, dimensions != nil) + return m +} + +// WithMargin customizes each margin individually - Left, Right, top and booton +// - if margin is null or individual margin is less than 0, margin will not be added +func (m *MarotoBuilder) WithMargin(margin *propsmapper.Margins) *MarotoBuilder { + if margin != nil { + validAndRun(func() { m.cfg.WithBottomMargin(margin.Bottom) }, margin.Bottom >= 0) + validAndRun(func() { m.cfg.WithTopMargin(margin.Top) }, margin.Top >= 0) + validAndRun(func() { m.cfg.WithLeftMargin(margin.Left) }, margin.Left >= 0) + validAndRun(func() { m.cfg.WithRightMargin(margin.Right) }, margin.Right >= 0) + } + return m +} + +// WithConcurrentMode defines concurrent generation, chunk workers define how mano chuncks will be executed concurrently. +// - if chunkWorkers is less than 0, will not be added +func (m *MarotoBuilder) WithConcurrentMode(chunkWorkers int) *MarotoBuilder { + validAndRun(func() { m.cfg.WithConcurrentMode(chunkWorkers) }, chunkWorkers > 0) + return m +} + +// WithSequentialMode defines that maroto will run in default mode. +func (m *MarotoBuilder) WithSequentialMode(on bool) *MarotoBuilder { + validAndRun(func() { m.cfg.WithSequentialMode() }, on) + return m +} + +// WithSequentialLowMemoryMode defines that maroto will run focusing in reduce memory consumption, +// chunk workers define how many divisions the work will have. +// - if chunkWorkers is less than 0, will not be added +func (m *MarotoBuilder) WithSequentialLowMemoryMode(chunkWorkers int) *MarotoBuilder { + validAndRun(func() { m.cfg.WithSequentialLowMemoryMode(chunkWorkers) }, chunkWorkers > 0) + return m +} + +// WithDebug defines a debug behaviour where maroto will draw borders in everything. +func (m *MarotoBuilder) WithDebug(on bool) *MarotoBuilder { + m.cfg.WithDebug(on) + return m +} + +// WithMaxGridSize defines a custom max grid sum which it will change the sum of column sizes. +// - if maxGridSize is less than 0, will not be added +func (m *MarotoBuilder) WithMaxGridSize(maxGridSize int) *MarotoBuilder { + validAndRun(func() { m.cfg.WithMaxGridSize(maxGridSize) }, maxGridSize > 0) + return m +} + +// WithDefaultFont defines a custom font, other than arial. This can be used to define a custom font as default. +// - if font is nill, will not be added +func (m *MarotoBuilder) WithDefaultFont(font *propsmapper.Font) *MarotoBuilder { + validAndRun(func() { + m.cfg.WithDefaultFont(&props.Font{ + Family: font.Family, Style: fontstyle.Type(font.Style), + Size: font.Size, Color: (*props.Color)(font.Color), + }) + }, font != nil) + return m +} + +// WithPageNumber defines a string pattern to write the current page and total. +// - if pageNumber is nill, will not be added +func (m *MarotoBuilder) WithPageNumber(pageNumber *propsmapper.PageNumber) *MarotoBuilder { + validAndRun(func() { + m.cfg.WithPageNumber(props.PageNumber{ + Pattern: pageNumber.Pattern, Place: props.Place(pageNumber.Place), Family: pageNumber.Family, + Style: fontstyle.Type(pageNumber.Style), Size: pageNumber.Size, + Color: (*props.Color)(pageNumber.Color), + }) + }, pageNumber != nil) + return m +} + +// WithProtection defines protection types to the PDF document. +// - if protectionmapper is nill, will not be added +func (m *MarotoBuilder) WithProtection(protectionmapper *propsmapper.Protection) *MarotoBuilder { + validAndRun(func() { + m.cfg.WithProtection(protection.Type(protectionmapper.Type), protectionmapper.UserPassword, protectionmapper.OwnerPassword) + }, protectionmapper != nil) + return m +} + +// WithCompression defines compression. +func (m *MarotoBuilder) WithCompression(compression bool) *MarotoBuilder { + m.cfg.WithCompression(compression) + return m +} + +// WithOrientation defines the page orientation. The default orientation is vertical, +// if horizontal is defined width and height will be flipped. +// - if orientationMapper is nill, will not be added +func (m *MarotoBuilder) WithOrientation(orientationMapper string) *MarotoBuilder { + validAndRun(func() { m.cfg.WithOrientation(orientation.Type(orientationMapper)) }, orientationMapper != "") + return m +} + +// WithMetadata customizes each metadata individually - Author, CreationDate, Creator, Keywords, subject and title +// - if metadata is null or individual metadata is less than 0, metadata will not be added +func (m *MarotoBuilder) WithMetadata(metadata *propsmapper.Metadata) *MarotoBuilder { + if metadata != nil { + validAndRun(func() { m.cfg.WithAuthor(metadata.Author.Text, metadata.Author.UTF8) }, metadata.Author != nil) + validAndRun(func() { m.cfg.WithCreationDate(*metadata.CreationDate) }, metadata.CreationDate != nil) + validAndRun(func() { m.cfg.WithCreator(metadata.Creator.Text, metadata.Creator.UTF8) }, metadata.Creator != nil) + validAndRun(func() { m.cfg.WithKeywords(metadata.KeywordsStr.Text, metadata.KeywordsStr.UTF8) }, metadata.KeywordsStr != nil) + validAndRun(func() { m.cfg.WithSubject(metadata.Subject.Text, metadata.Subject.UTF8) }, metadata.Subject != nil) + validAndRun(func() { m.cfg.WithTitle(metadata.Title.Text, metadata.Title.UTF8) }, metadata.Title != nil) + } + return m +} + +// WithCustomFonts add custom fonts. +// - if the font file cannot be loaded, an error will be returned +func (m *MarotoBuilder) WithCustomFonts(customFonts []*propsmapper.CustomFont) (*MarotoBuilder, error) { + if len(customFonts) == 0 { + return m, nil + } + newFonts, err := m.loadFonts(customFonts) + if err != nil { + return nil, err + } + m.cfg.WithCustomFonts(newFonts) + return m, nil +} + +// WithBackgroundImage defines the background image that will be applied in every page. +// - if the image file cannot be loaded, an error will be returned +func (m *MarotoBuilder) WithBackgroundImage(backgroundImage string) (*MarotoBuilder, error) { + if backgroundImage == "" { + return m, nil + } + + ext, imageBytes, err := m.repository.GetDocument(backgroundImage) + if err != nil { + return nil, err + } + m.cfg.WithBackgroundImage(imageBytes, extension.Type(ext)) + return m, nil +} + +// WithDisableAutoPageBreak defines the option to disable automatic page breaks. +func (m *MarotoBuilder) WithDisableAutoPageBreak(disabled bool) *MarotoBuilder { + m.cfg.WithDisableAutoPageBreak(disabled) + return m +} + +func validAndRun(setParam func(), parameter bool) { + if parameter { + setParam() + } +} + +func (m *MarotoBuilder) loadFonts(customFonts []*propsmapper.CustomFont) ([]*entity.CustomFont, error) { + fontRepository := repository.New() + + for _, customFont := range customFonts { + _, fontBytes, err := m.repository.GetDocument(customFont.File) + if err != nil { + return nil, err + } + fontRepository.AddUTF8FontFromBytes(customFont.Family, fontstyle.Type(customFont.Style), fontBytes) + } + return fontRepository.Load() +} diff --git a/pkg/processor/processorprovider/builder_maroto_test.go b/pkg/processor/processorprovider/builder_maroto_test.go new file mode 100644 index 00000000..44fc3c1d --- /dev/null +++ b/pkg/processor/processorprovider/builder_maroto_test.go @@ -0,0 +1,688 @@ +package processorprovider_test + +import ( + "fmt" + "testing" + + "github.com/johnfercher/maroto/v2/internal/fixture" + "github.com/johnfercher/maroto/v2/mocks" + "github.com/johnfercher/maroto/v2/pkg/config" + "github.com/johnfercher/maroto/v2/pkg/consts/extension" + "github.com/johnfercher/maroto/v2/pkg/consts/orientation" + "github.com/johnfercher/maroto/v2/pkg/consts/pagesize" + "github.com/johnfercher/maroto/v2/pkg/consts/protection" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" + "github.com/johnfercher/maroto/v2/pkg/processor/processorprovider" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +func NewBuilderMocks(t *testing.T) *mocks.Builder { + build := mocks.NewBuilder(t) + build.EXPECT().WithPageSize(mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithDimensions(mock.Anything, mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithTopMargin(mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithBottomMargin(mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithLeftMargin(mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithRightMargin(mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithConcurrentMode(mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithDebug(mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithMaxGridSize(mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithDefaultFont(mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithPageNumber(mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithProtection(mock.Anything, mock.Anything, mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithCompression(mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithOrientation(mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithAuthor(mock.Anything, mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithCreationDate(mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithCreator(mock.Anything, mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithKeywords(mock.Anything, mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithSubject(mock.Anything, mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithTitle(mock.Anything, mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithDisableAutoPageBreak(mock.Anything).Return(config.NewBuilder()) + build.EXPECT().WithCustomFonts(mock.Anything).Return(config.NewBuilder()) + return build +} + +func NewvalidateCallOfAllMethods(t *testing.T, builder *mocks.Builder) { + builder.AssertNumberOfCalls(t, "WithPageSize", 1) + builder.AssertNumberOfCalls(t, "WithDimensions", 1) + builder.AssertNumberOfCalls(t, "WithTopMargin", 1) + builder.AssertNumberOfCalls(t, "WithBottomMargin", 1) + builder.AssertNumberOfCalls(t, "WithLeftMargin", 1) + builder.AssertNumberOfCalls(t, "WithRightMargin", 1) + builder.AssertNumberOfCalls(t, "WithConcurrentMode", 1) + builder.AssertNumberOfCalls(t, "WithSequentialMode", 0) + builder.AssertNumberOfCalls(t, "WithDebug", 1) + builder.AssertNumberOfCalls(t, "WithMaxGridSize", 1) + builder.AssertNumberOfCalls(t, "WithDefaultFont", 1) + builder.AssertNumberOfCalls(t, "WithPageNumber", 1) + builder.AssertNumberOfCalls(t, "WithProtection", 1) + builder.AssertNumberOfCalls(t, "WithCompression", 1) + builder.AssertNumberOfCalls(t, "WithOrientation", 1) + builder.AssertNumberOfCalls(t, "WithAuthor", 1) + builder.AssertNumberOfCalls(t, "WithCreationDate", 1) + builder.AssertNumberOfCalls(t, "WithCreator", 1) + builder.AssertNumberOfCalls(t, "WithKeywords", 1) + builder.AssertNumberOfCalls(t, "WithSubject", 1) + builder.AssertNumberOfCalls(t, "WithTitle", 1) + builder.AssertNumberOfCalls(t, "WithDisableAutoPageBreak", 1) + builder.AssertNumberOfCalls(t, "WithCustomFonts", 1) +} + +func TestCreateMarotoBuilder(t *testing.T) { + t.Run("when all props are sent, should add all props", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + repository.EXPECT().GetDocument(mock.Anything).Return(string(extension.Png), []byte{123}, nil) + build := NewBuilderMocks(t) + fixProps := fixture.BuilderProps() + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg, err := builder.CreateMarotoBuilder(fixProps) + + assert.Nil(t, err) + assert.NotNil(t, cfg) + NewvalidateCallOfAllMethods(t, build) + }) +} + +func TestWithPageSize(t *testing.T) { + t.Run("when page size is null, should not set page size", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithPageSize("") + + assert.NotNil(t, cfg) + }) + t.Run("when page size is sent, should set page size", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithPageSize(pagesize.A1).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithPageSize("a1") + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithPageSize", 1) + }) +} + +func TestWithDimensions(t *testing.T) { + t.Run("when dimensions is nil, should not set dimensions", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithDimensions(nil) + + assert.NotNil(t, cfg) + }) + t.Run("when dimensions is sent, should set dimensions", func(t *testing.T) { + fixDimensions := propsmapper.Dimensions{Width: 10.0, Height: 10.0} + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithDimensions(fixDimensions.Width, fixDimensions.Height).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithDimensions(&fixDimensions) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithDimensions", 1) + }) +} + +func TestWithMargins(t *testing.T) { + t.Run("when only left margin is sent, should set only left margin", func(t *testing.T) { + fixMargins := propsmapper.Margins{Left: 10, Right: -1, Top: -1, Bottom: -1} + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithLeftMargin(fixMargins.Left).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMargin(&fixMargins) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithLeftMargin", 1) + }) + t.Run("when only right margin is sent, should set only right margin", func(t *testing.T) { + fixMargins := propsmapper.Margins{Left: -1, Right: 10, Top: -1, Bottom: -1} + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithRightMargin(fixMargins.Right).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMargin(&fixMargins) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithRightMargin", 1) + }) + t.Run("when only bottom margin is sent, should set only bottom margin", func(t *testing.T) { + fixMargins := propsmapper.Margins{Left: -1, Right: -1, Top: 10, Bottom: -1} + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithTopMargin(fixMargins.Top).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMargin(&fixMargins) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithTopMargin", 1) + }) + t.Run("when only top margin is sent, should set only top margin", func(t *testing.T) { + fixMargins := propsmapper.Margins{Left: -1, Right: -1, Top: -1, Bottom: 10} + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithBottomMargin(fixMargins.Bottom).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMargin(&fixMargins) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithBottomMargin", 1) + }) + t.Run("When margins is not set, should no set margin", func(t *testing.T) { + fixMargins := propsmapper.Margins{Left: 10, Right: 11, Top: 12, Bottom: 13} + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithBottomMargin(fixMargins.Bottom).Return(config.NewBuilder()) + build.EXPECT().WithTopMargin(fixMargins.Top).Return(config.NewBuilder()) + build.EXPECT().WithLeftMargin(fixMargins.Left).Return(config.NewBuilder()) + build.EXPECT().WithRightMargin(fixMargins.Right).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMargin(&fixMargins) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithBottomMargin", 1) + build.AssertNumberOfCalls(t, "WithTopMargin", 1) + build.AssertNumberOfCalls(t, "WithLeftMargin", 1) + build.AssertNumberOfCalls(t, "WithRightMargin", 1) + }) +} + +func TestWithConcurrentMode(t *testing.T) { + t.Run("when 0 works is sent, should not set concurrent Mode", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithConcurrentMode(0) + + assert.NotNil(t, cfg) + }) + t.Run("when 2 works are sent, should set concurrent mode", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithConcurrentMode(2).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithConcurrentMode(2) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithConcurrentMode", 1) + }) +} + +func TestWithSequentialMode(t *testing.T) { + t.Run("when sequential mode is true, should set sequential mode", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithSequentialMode().Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithSequentialMode(true) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithSequentialMode", 1) + }) + t.Run("when sequential mode is false, should not set sequential mode", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithSequentialMode(false) + + assert.NotNil(t, cfg) + }) +} + +func TestWithSequentialLowMemoryMode(t *testing.T) { + t.Run("when sequential low memory mode is 0, should not set sequential low memory", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithSequentialLowMemoryMode(0) + + assert.NotNil(t, cfg) + }) + + t.Run("when sequential low memory mode is 2, should set sequential low memory", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithSequentialLowMemoryMode(2).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithSequentialLowMemoryMode(2) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithSequentialLowMemoryMode", 1) + }) +} + +func TestWithDebug(t *testing.T) { + t.Run("when debug is true, should set debug", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithDebug(true).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithDebug(true) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithDebug", 1) + }) + t.Run("when debug is false, should not set debug", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithDebug(false).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithDebug(false) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithDebug", 1) + }) +} + +func TestWithMaxGridSize(t *testing.T) { + t.Run("when max grid size is 0, should not set max grid size", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMaxGridSize(0) + + assert.NotNil(t, cfg) + }) + + t.Run("when max grid size is 2, should set max grid size with 2", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithMaxGridSize(2).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMaxGridSize(2) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithMaxGridSize", 1) + }) +} + +func TestWithDefaultFont(t *testing.T) { + t.Run("when font is nil, should not set font", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithDefaultFont(nil) + + assert.NotNil(t, cfg) + }) + t.Run("when invalid style is call, should set font", func(t *testing.T) { + fixFont := fixture.FontProp() + fixFont.Style = "invalid" + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithDefaultFont(&fixFont).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithDefaultFont(&propsmapper.Font{ + Family: fixFont.Family, + Style: string(fixFont.Style), Size: fixFont.Size, Color: (*propsmapper.Color)(fixFont.Color), + }) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithDefaultFont", 1) + }) + t.Run("when font is sent, should set font", func(t *testing.T) { + fixFont := fixture.FontProp() + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithDefaultFont(&fixFont).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithDefaultFont(&propsmapper.Font{ + Family: fixFont.Family, + Style: string(fixFont.Style), Size: fixFont.Size, Color: (*propsmapper.Color)(fixFont.Color), + }) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithDefaultFont", 1) + }) +} + +func TestWithPageNumber(t *testing.T) { + t.Run("when page number is nil, should not set page number", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithPageNumber(nil) + + assert.NotNil(t, cfg) + }) + t.Run("when page number is sent, should set page number", func(t *testing.T) { + fixPageNumber := fixture.PageProp() + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithPageNumber(fixPageNumber).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithPageNumber(&propsmapper.PageNumber{ + Pattern: fixPageNumber.Pattern, Place: string(fixPageNumber.Place), Family: fixPageNumber.Family, + Style: string(fixPageNumber.Style), Size: fixPageNumber.Size, Color: (*propsmapper.Color)(fixPageNumber.Color), + }) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithPageNumber", 1) + }) +} + +func TestWithProtection(t *testing.T) { + t.Run("when protection is nil, should not set protection", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithProtection(nil) + + assert.NotNil(t, cfg) + }) + + t.Run("when protection is sent, should set protection", func(t *testing.T) { + fixProtection := propsmapper.Protection{Type: 0, UserPassword: "user.password", OwnerPassword: "pass"} + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithProtection(protection.Type(fixProtection.Type), fixProtection.UserPassword, + fixProtection.OwnerPassword).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithProtection(&fixProtection) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithProtection", 1) + }) +} + +func TestWithCompression(t *testing.T) { + t.Run("when compression is true, should set compression", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithCompression(true).Return(config.NewBuilder()) + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithCompression(true) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithCompression", 1) + }) +} + +func TestWithOrientation(t *testing.T) { + t.Run("when orientation is null, should not set orientation", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithOrientation("") + + assert.NotNil(t, cfg) + }) + t.Run("when orientation is sent, should set orientation", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithOrientation(orientation.Vertical).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithOrientation("vertical") + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithOrientation", 1) + }) +} + +func TestWithMetadata(t *testing.T) { + t.Run("when metadata is nil, should not set any metadata", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMetadata(nil) + + assert.NotNil(t, cfg) + }) + t.Run("when only author is sent, should set only author", func(t *testing.T) { + fixMetadata := fixture.Metadata() + fixMetadata.CreationDate = nil + fixMetadata.Creator = nil + fixMetadata.Subject = nil + fixMetadata.KeywordsStr = nil + fixMetadata.Title = nil + + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithAuthor(fixMetadata.Author.Text, fixMetadata.Author.UTF8).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMetadata(fixMetadata) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithAuthor", 1) + }) + t.Run("when creation date is nil, should not set creation date", func(t *testing.T) { + fixMetadata := fixture.Metadata() + fixMetadata.Author = nil + fixMetadata.Creator = nil + fixMetadata.Subject = nil + fixMetadata.KeywordsStr = nil + fixMetadata.Title = nil + + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithCreationDate(*fixMetadata.CreationDate).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMetadata(fixMetadata) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithCreationDate", 1) + }) + t.Run("when creator is nil, should not set creator", func(t *testing.T) { + fixMetadata := fixture.Metadata() + fixMetadata.Author = nil + fixMetadata.CreationDate = nil + fixMetadata.Subject = nil + fixMetadata.KeywordsStr = nil + fixMetadata.Title = nil + + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithCreator(fixMetadata.Creator.Text, fixMetadata.Creator.UTF8).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMetadata(fixMetadata) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithCreator", 1) + }) + t.Run("when keywords is nil, should not set keywords", func(t *testing.T) { + fixMetadata := fixture.Metadata() + fixMetadata.Author = nil + fixMetadata.CreationDate = nil + fixMetadata.Subject = nil + fixMetadata.Creator = nil + fixMetadata.Title = nil + + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithKeywords(fixMetadata.KeywordsStr.Text, fixMetadata.KeywordsStr.UTF8).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMetadata(fixMetadata) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithKeywords", 1) + }) + t.Run("when subject is nil, should not set subject", func(t *testing.T) { + fixMetadata := fixture.Metadata() + fixMetadata.Author = nil + fixMetadata.CreationDate = nil + fixMetadata.KeywordsStr = nil + fixMetadata.Creator = nil + fixMetadata.Title = nil + + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithSubject(fixMetadata.Subject.Text, fixMetadata.Subject.UTF8).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMetadata(fixMetadata) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithSubject", 1) + }) + t.Run("when title is nil, should not set title", func(t *testing.T) { + fixMetadata := fixture.Metadata() + fixMetadata.Author = nil + fixMetadata.CreationDate = nil + fixMetadata.KeywordsStr = nil + fixMetadata.Creator = nil + fixMetadata.Subject = nil + + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithTitle(fixMetadata.Title.Text, fixMetadata.Title.UTF8).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMetadata(fixMetadata) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithTitle", 1) + }) + t.Run("when all metadatas is sent, should set all metadatas", func(t *testing.T) { + fixMetadata := fixture.Metadata() + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithAuthor(fixMetadata.Author.Text, fixMetadata.Author.UTF8).Return(config.NewBuilder()) + build.EXPECT().WithCreationDate(*fixMetadata.CreationDate).Return(config.NewBuilder()) + build.EXPECT().WithCreator(fixMetadata.Creator.Text, fixMetadata.Creator.UTF8).Return(config.NewBuilder()) + build.EXPECT().WithKeywords(fixMetadata.KeywordsStr.Text, fixMetadata.KeywordsStr.UTF8).Return(config.NewBuilder()) + build.EXPECT().WithSubject(fixMetadata.Subject.Text, fixMetadata.Subject.UTF8).Return(config.NewBuilder()) + build.EXPECT().WithTitle(fixMetadata.Title.Text, fixMetadata.Title.UTF8).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithMetadata(fixMetadata) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithAuthor", 1) + build.AssertNumberOfCalls(t, "WithCreationDate", 1) + build.AssertNumberOfCalls(t, "WithCreator", 1) + build.AssertNumberOfCalls(t, "WithKeywords", 1) + build.AssertNumberOfCalls(t, "WithSubject", 1) + build.AssertNumberOfCalls(t, "WithTitle", 1) + }) +} + +func TestWithCustomFonts(t *testing.T) { + t.Run("when fonts is not sent, should not set fonts", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg, err := builder.WithCustomFonts(nil) + + assert.Nil(t, err) + assert.NotNil(t, cfg) + }) + t.Run("when is not possible load font file, should return an error", func(t *testing.T) { + fixCustomFont := propsmapper.CustomFont{Family: "family", Style: "bold", File: "file"} + repository := mocks.NewProcessorRepository(t) + repository.EXPECT().GetDocument(fixCustomFont.File).Return("", nil, fmt.Errorf("any")) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg, err := builder.WithCustomFonts([]*propsmapper.CustomFont{&fixCustomFont}) + + assert.NotNil(t, err) + assert.Nil(t, cfg) + }) + t.Run("when 2 fonts is sent, should set 2 fonts", func(t *testing.T) { + fixCustomFont := propsmapper.CustomFont{Family: "family", Style: "bold", File: "file"} + repository := mocks.NewProcessorRepository(t) + repository.EXPECT().GetDocument(fixCustomFont.File).Return(".ttt", []byte{}, nil) + build := mocks.NewBuilder(t) + build.EXPECT().WithCustomFonts(mock.Anything).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg, err := builder.WithCustomFonts([]*propsmapper.CustomFont{&fixCustomFont, &fixCustomFont}) + + assert.Nil(t, err) + assert.NotNil(t, cfg) + repository.AssertNumberOfCalls(t, "GetDocument", 2) + build.AssertNumberOfCalls(t, "WithCustomFonts", 1) + }) +} + +func TestWithBackgroundImage(t *testing.T) { + t.Run("when background image is not sent, should not set background image", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg, err := builder.WithCustomFonts(nil) + + assert.Nil(t, err) + assert.NotNil(t, cfg) + }) + t.Run("when is not possible load image, should return an error", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + repository.EXPECT().GetDocument("img").Return("", nil, fmt.Errorf("any")) + build := mocks.NewBuilder(t) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg, err := builder.WithBackgroundImage("img") + + assert.NotNil(t, err) + assert.Nil(t, cfg) + }) + t.Run("when backgroun image is sent, should set background", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + repository.EXPECT().GetDocument("img").Return(string(extension.Png), []byte{123}, nil) + build := mocks.NewBuilder(t) + build.EXPECT().WithBackgroundImage([]byte{123}, extension.Png).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg, err := builder.WithBackgroundImage("img") + + assert.Nil(t, err) + assert.NotNil(t, cfg) + repository.AssertNumberOfCalls(t, "GetDocument", 1) + build.AssertNumberOfCalls(t, "WithBackgroundImage", 1) + }) +} + +func TestWithDisableAutoPageBreak(t *testing.T) { + t.Run("when disable auto page break is true, should disable auto page break", func(t *testing.T) { + repository := mocks.NewProcessorRepository(t) + build := mocks.NewBuilder(t) + build.EXPECT().WithDisableAutoPageBreak(true).Return(config.NewBuilder()) + + builder := processorprovider.NewMarotoBuilder(repository, build) + cfg := builder.WithDisableAutoPageBreak(true) + + assert.NotNil(t, cfg) + build.AssertNumberOfCalls(t, "WithDisableAutoPageBreak", 1) + }) +} diff --git a/pkg/processor/processorprovider/provider.go b/pkg/processor/processorprovider/provider.go new file mode 100644 index 00000000..359aa02d --- /dev/null +++ b/pkg/processor/processorprovider/provider.go @@ -0,0 +1,31 @@ +package processorprovider + +import ( + "github.com/johnfercher/go-tree/node" + "github.com/johnfercher/maroto/v2/pkg/core" + "github.com/johnfercher/maroto/v2/pkg/processor/mappers/propsmapper" +) + +type ProviderComponent interface { + core.Node +} + +// ProcessorProvider provides an interface with all the methods that +// Maroto provides for pdf builder +type ProcessorProvider interface { + Generate() (core.Document, error) + GetStructure() *node.Node[core.Structure] + AddPages(pages ...ProviderComponent) (ProcessorProvider, error) + AddFooter(footer ...ProviderComponent) (ProcessorProvider, error) + AddHeader(header ...ProviderComponent) (ProcessorProvider, error) + CreatePage(components ...ProviderComponent) (ProviderComponent, error) + CreateRow(height float64, props *propsmapper.Cell, components ...ProviderComponent) (ProviderComponent, error) + CreateCol(size int, props *propsmapper.Cell, components ...ProviderComponent) (ProviderComponent, error) + CreateText(value string, props ...*propsmapper.Text) ProviderComponent + CreateSignature(value string, props ...*propsmapper.Signature) ProviderComponent + CreateBarCode(value string, props ...*propsmapper.Barcode) ProviderComponent + CreateMatrixCode(value string, props ...*propsmapper.Rect) ProviderComponent + CreateQrCode(value string, props ...*propsmapper.Rect) ProviderComponent + CreateImage(path string, props ...*propsmapper.Rect) (ProviderComponent, error) + CreateLine(props ...*propsmapper.Line) ProviderComponent +} diff --git a/pkg/processor/repository/memory_storage.go b/pkg/processor/repository/memory_storage.go new file mode 100644 index 00000000..a59ee008 --- /dev/null +++ b/pkg/processor/repository/memory_storage.go @@ -0,0 +1,51 @@ +// repository package is responsible for managing access to templates +package repository + +import ( + "github.com/johnfercher/maroto/v2/pkg/processor/core" +) + +type memoryStorage struct { + template map[string]map[string]any + documents map[string][]byte + loader core.Loader +} + +// NewMemoryStorage is responsible for creating a repository +// implementation that stores data in memory +func NewMemoryStorage(loader core.Loader) *memoryStorage { + return &memoryStorage{ + template: make(map[string]map[string]any), + loader: loader, + documents: make(map[string][]byte), + } +} + +// GetDocument is responsible search and return the document according to the name sent +// - documentName is the name that the document references +func (m *memoryStorage) GetDocument(documentPath string) (string, []byte, error) { + if doc, ok := m.documents[documentPath]; ok { + return m.loader.GetExt(documentPath), doc, nil + } + + bytes, err := m.loader.Load(documentPath) + if err != nil { + return "", nil, err + } + m.documents[documentPath] = bytes + return m.loader.GetExt(documentPath), bytes, nil +} + +// RegisterTemplate is responsible for register a template in memory +// - name is the model identifier and is used to access it +// - template is the template that will be stored +func (m *memoryStorage) RegisterTemplate(name string, template map[string]any) error { + m.template[name] = template + return nil +} + +// ReadTemplate is responsible for fetching the stored template +// - name is the model identifier and is used to access it +func (m *memoryStorage) ReadTemplate(templateName string) (map[string]any, error) { + return m.template[templateName], nil +} diff --git a/pkg/processor/test/File.go b/pkg/processor/test/File.go new file mode 100644 index 00000000..1c63e795 --- /dev/null +++ b/pkg/processor/test/File.go @@ -0,0 +1,118 @@ +package test + +import ( + "errors" + "os" + "strings" + + "gopkg.in/yaml.v3" +) + +var ( + marotoFile = ".maroto.yml" + goModFile = "go.mod" + fileSingleton *File = nil +) + +type File struct { + config *Config +} + +func NewFileReader() *File { + if fileSingleton == nil { + path, err := getMarotoConfigFilePath() + if err != nil { + return nil + } + + cfg, err := loadMarotoConfigFile(path) + if err != nil { + return nil + } + + cfg.AbsolutePath = path + fileSingleton = &File{config: cfg} + } + + return fileSingleton +} + +func (f File) LoadFile(file string) ([]byte, error) { + fileContent, err := os.ReadFile(f.config.getAbsoluteFilePath(file)) + if err != nil { + return nil, err + } + return fileContent, err +} + +func getMarotoConfigFilePath() (string, error) { + path, _ := os.Getwd() + path += "/" + + return getMarotoConfigFilePathRecursive(path) +} + +func getMarotoConfigFilePathRecursive(path string) (string, error) { + hasMaroto, err := hasFileInPath(marotoFile, path) + if err != nil { + return "", err + } + + if hasMaroto { + return path, nil + } + + hasGoMod, err := hasFileInPath(goModFile, path) + if err != nil { + return "", err + } + + if hasGoMod { + return "", errors.New("found go.mod but not .maroto.yml") + } + + parentPath := getParentDir(path) + return getMarotoConfigFilePathRecursive(parentPath) +} + +func hasFileInPath(file string, path string) (bool, error) { + entries, err := os.ReadDir(path) + if err != nil { + return false, err + } + + for _, entry := range entries { + if entry.Name() == file { + return true, nil + } + } + + return false, nil +} + +func getParentDir(path string) string { + dirs := strings.Split(path, "/") + dirs = dirs[:len(dirs)-2] + + var newPath string + for _, dir := range dirs { + newPath += dir + "/" + } + + return newPath +} + +func loadMarotoConfigFile(path string) (*Config, error) { + bytes, err := os.ReadFile(path + "/" + marotoFile) + if err != nil { + return nil, err + } + + cfg := &Config{} + err = yaml.Unmarshal(bytes, cfg) + if err != nil { + return nil, err + } + + return cfg, nil +} diff --git a/pkg/processor/test/config.go b/pkg/processor/test/config.go new file mode 100644 index 00000000..63f335dc --- /dev/null +++ b/pkg/processor/test/config.go @@ -0,0 +1,12 @@ +// Package test implements unit test feature. +package test + +// Config is the representation of a test config. +type Config struct { + AbsolutePath string + TestPath string `yaml:"test_path"` +} + +func (c *Config) getAbsoluteFilePath(file string) string { + return c.AbsolutePath + c.TestPath + file +} diff --git a/pkg/test/test.go b/pkg/test/test.go index 7ab68db2..aa1cc590 100644 --- a/pkg/test/test.go +++ b/pkg/test/test.go @@ -10,6 +10,7 @@ import ( "github.com/johnfercher/go-tree/node" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" "github.com/johnfercher/maroto/v2/pkg/core" @@ -34,6 +35,22 @@ type MarotoTest struct { node *node.Node[core.Structure] } +// SetupTestDir sets the directory where the test will be built +// after the test is finished, the original directory will be set +func SetupTestDir(t *testing.T) { + New(t) + originalDir, err := os.Getwd() + require.NoError(t, err) + + err = os.Chdir(configSingleton.AbsolutePath) + require.NoError(t, err) + + defer t.Cleanup(func() { + err := os.Chdir(originalDir) + require.NoError(t, err) + }) +} + // New creates the MarotoTest instance to unit tests. func New(t *testing.T) *MarotoTest { if configSingleton == nil { diff --git a/pkg/test/test_test.go b/pkg/test/test_test.go index c929193a..56e4a6ad 100644 --- a/pkg/test/test_test.go +++ b/pkg/test/test_test.go @@ -14,6 +14,16 @@ const ( file = "maroto_test.json" ) +func TestSetupTestDir(t *testing.T) { + t.Run("when directory is setup correctly, it should load maroto.yml", func(t *testing.T) { + SetupTestDir(t) + + _, err := os.Open(".maroto.yml") + + assert.Nil(t, err) + }) +} + func TestNew(t *testing.T) { t.Run("when called first, should setup singleton and set t", func(t *testing.T) { // Act diff --git a/test/maroto/examples/autorow.json b/test/maroto/examples/autorow.json index ccc53a65..d739323c 100755 --- a/test/maroto/examples/autorow.json +++ b/test/maroto/examples/autorow.json @@ -21,7 +21,7 @@ "type": "page", "nodes": [ { - "value": 38.80555555555556, + "value": 62.36222222222222, "type": "row", "nodes": [ { @@ -168,6 +168,21 @@ } ] }, + { + "value": 23.946388888888862, + "type": "row", + "nodes": [ + { + "value": 12, + "type": "col" + } + ] + } + ] + }, + { + "type": "page", + "nodes": [ { "value": 47.5, "type": "row", @@ -204,21 +219,6 @@ } ] }, - { - "value": 0.0030555555555338287, - "type": "row", - "nodes": [ - { - "value": 12, - "type": "col" - } - ] - } - ] - }, - { - "type": "page", - "nodes": [ { "value": 31.666666666666664, "type": "row", @@ -256,7 +256,7 @@ ] }, { - "value": 235.33083333333335, + "value": 187.83083333333335, "type": "row", "nodes": [ { diff --git a/test/maroto/examples/imagegrid.json b/test/maroto/examples/imagegrid.json index 807d6eaf..d628188f 100755 --- a/test/maroto/examples/imagegrid.json +++ b/test/maroto/examples/imagegrid.json @@ -283,7 +283,22 @@ ] }, { - "value": 0, + "value": 26.997500000000002, + "type": "row", + "nodes": [ + { + "value": 12, + "type": "col" + } + ] + } + ] + }, + { + "type": "page", + "nodes": [ + { + "value": 51.67999999999999, "type": "row", "nodes": [ { @@ -319,7 +334,7 @@ ] }, { - "value": 0, + "value": 52.41733333333333, "type": "row", "nodes": [ { @@ -371,7 +386,7 @@ ] }, { - "value": 26.997500000000002, + "value": 162.90016666666668, "type": "row", "nodes": [ { diff --git a/test/maroto/processor/all_builder_pros.json b/test/maroto/processor/all_builder_pros.json new file mode 100644 index 00000000..19d338ca --- /dev/null +++ b/test/maroto/processor/all_builder_pros.json @@ -0,0 +1,60 @@ +{ + "dimensions": { + "width": 10.0, + "height": 10.0 + }, + "margins": { + "left": 10, + "right": 10, + "top": 10, + "bottom": 10 + }, + "concurrent_mode": 10, + "sequential_mode": false, + "debug": true, + "max_grid_size": 10, + "default_font": { + "family": "Arial", + "style": "bold", + "size": 10, + "color": { + "red": 10, + "green": 100, + "blue": 150 + } + }, + "page_number":{ + "pattern": "pattern_test", + "place": "place_test", + "family": "family_test", + "style": "italic", + "size": 10, + "color": { + "red": 10, + "green": 100, + "blue": 150 + } + }, + "custom_fonts": [ + {"family": "family_test", "style": "bold", "file_path": "file_test"}, + {"family": "family_test2", "style": "bold", "file_path": "file_test2"} + ], + "protection": { + "type": "print", + "user_password": "senha123", + "owner_password": "senha123" + }, + "compression": true, + "page_size": "T", + "orientation": "vertical", + "metadata": { + "author": {"text": "user_test", "utf8": true}, + "creator": {"text": "user_test", "utf8": true}, + "subject": {"text": "test", "utf8": true}, + "title": {"text": "report", "utf8": true}, + "creation_date": "2024-10-09 14:30:00", + "keywords": {"text": "test", "utf8": true} + }, + "disable_auto_page_break": true, + "generation_mode": "concurrent" +} \ No newline at end of file diff --git a/test/maroto/processor/json/add_page_content.json b/test/maroto/processor/json/add_page_content.json new file mode 100644 index 00000000..6fa0d5d8 --- /dev/null +++ b/test/maroto/processor/json/add_page_content.json @@ -0,0 +1,69 @@ +{ + "pages": { + "template_page_1": { + "list_rows": [ + { + "row_1": { + "page_1_row": "page1 row1" + } + }, + { + "row_1": { + "page_1_row": "page1 row2" + } + }, + { + "row_1": { + "page_1_row": "page1 row3" + } + }, + { + "row_1": { + "page_1_row": "page1 row4" + } + }, + { + "row_1": { + "page_1_row": "page1 row5" + } + }, + { + "row_1": { + "page_1_row": "page1 row6" + } + }, + { + "row_1": { + "page_1_row": "page1 row7" + } + }, + { + "row_1": { + "page_1_row": "page1 row8" + } + }, + { + "row_1": { + "page_1_row": "page1 row9" + } + } + ] + }, + "list_pages": [ + { + "template_page_2": { + "row_1": { + "page_2_row": "page2 row1" + } + } + }, + { + "template_page_2": { + "row_1": { + "page_2_row": "page3 row1" + } + } + } + ] + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/add_page_template.json b/test/maroto/processor/json/add_page_template.json new file mode 100644 index 00000000..bc28b0d2 --- /dev/null +++ b/test/maroto/processor/json/add_page_template.json @@ -0,0 +1,44 @@ +{ + "builder": { + "page_number": {}, + "debug": true + }, + "pages": { + "template_page_1": { + "order": 1, + "list_rows": { + "order": 1, + "row_1": { + "order": 1, + "height": 30, + "cols": [ + { + "text": { + "order": 1, + "source_key": "page_1_row" + } + } + ] + } + } + }, + "list_pages": { + "order":2, + "template_page_2": { + "order": 1, + "row_1": { + "order": 1, + "height": 10, + "cols": [ + { + "text": { + "order": 1, + "source_key": "page_2_row" + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/auto_row_content.json b/test/maroto/processor/json/auto_row_content.json new file mode 100644 index 00000000..c9470dd3 --- /dev/null +++ b/test/maroto/processor/json/auto_row_content.json @@ -0,0 +1,30 @@ +{ + "pages": { + "page_template": { + "row_with_larger_image": { + "biplane": "docs/assets/images/biplane.jpg", + "intro": "Numa toca no chão vivia um hobbit. Não uma toca nojenta, suja, úmida, \ncheia de pontas de minhocas e um cheiro de limo, nem tam pouco uma toca seca, vazia, arenosa, \nsem nenhum lugar onde se sentar ou onde comer: era uma toca de hobbit, e isso significa conforto.\nEla tinha uma porta perfeitamente redonda feito uma escotilha, pintada de verde, com uma maçaneta\namarela e brilhante de latão exatamente no meio. A porta se abria para um corredor em forma de tubo,\nfeito um túnel: um túnel muito confortável, sem fumaça, de paredes com painéis e assoalhos\nazulejados e acarpetados, com cadeiras enceradas e montes e montes de cabieiros para chapéus e\ncasacos - o hobbit apreciava visitas." + }, + "row_with_image_and_text_same": { + "biplane": "docs/assets/images/biplane.jpg", + "intro": "Numa toca no chão vivia um hobbit. Não uma toca nojenta, suja, úmida, \ncheia de pontas de minhocas e um cheiro de limo, nem tam pouco uma toca seca, vazia, arenosa, \nsem nenhum lugar onde se sentar ou onde comer: era uma toca de hobbit, e isso significa conforto.\nEla tinha uma porta perfeitamente redonda feito uma escotilha, pintada de verde, com uma maçaneta\namarela e brilhante de latão exatamente no meio. A porta se abria para um corredor em forma de tubo,\nfeito um túnel: um túnel muito confortável, sem fumaça, de paredes com painéis e assoalhos\nazulejados e acarpetados, com cadeiras enceradas e montes e montes de cabieiros para chapéus e\ncasacos - o hobbit apreciava visitas." + }, + "row_with_image2": { + "biplane": "docs/assets/images/biplane.jpg", + "intro": "Numa toca no chão vivia um hobbit. Não uma toca nojenta, suja, úmida, \ncheia de pontas de minhocas e um cheiro de limo, nem tam pouco uma toca seca, vazia, arenosa, \nsem nenhum lugar onde se sentar ou onde comer: era uma toca de hobbit, e isso significa conforto.\nEla tinha uma porta perfeitamente redonda feito uma escotilha, pintada de verde, com uma maçaneta\namarela e brilhante de latão exatamente no meio. A porta se abria para um corredor em forma de tubo,\nfeito um túnel: um túnel muito confortável, sem fumaça, de paredes com painéis e assoalhos\nazulejados e acarpetados, com cadeiras enceradas e montes e montes de cabieiros para chapéus e\ncasacos - o hobbit apreciava visitas." + }, + "row_barcode": { + "bar_col": "code", + "intro": "Numa toca no chão vivia um hobbit. Não uma toca nojenta, suja, úmida, \ncheia de pontas de minhocas e um cheiro de limo, nem tam pouco uma toca seca, vazia, arenosa, \nsem nenhum lugar onde se sentar ou onde comer: era uma toca de hobbit, e isso significa conforto.\nEla tinha uma porta perfeitamente redonda feito uma escotilha, pintada de verde, com uma maçaneta\namarela e brilhante de latão exatamente no meio. A porta se abria para um corredor em forma de tubo,\nfeito um túnel: um túnel muito confortável, sem fumaça, de paredes com painéis e assoalhos\nazulejados e acarpetados, com cadeiras enceradas e montes e montes de cabieiros para chapéus e\ncasacos - o hobbit apreciava visitas." + }, + "row_matrixcode": { + "matrix_code": "code", + "intro": "Numa toca no chão vivia um hobbit. Não uma toca nojenta, suja, úmida, \ncheia de pontas de minhocas e um cheiro de limo, nem tam pouco uma toca seca, vazia, arenosa, \nsem nenhum lugar onde se sentar ou onde comer: era uma toca de hobbit, e isso significa conforto.\nEla tinha uma porta perfeitamente redonda feito uma escotilha, pintada de verde, com uma maçaneta\namarela e brilhante de latão exatamente no meio. A porta se abria para um corredor em forma de tubo,\nfeito um túnel: um túnel muito confortável, sem fumaça, de paredes com painéis e assoalhos\nazulejados e acarpetados, com cadeiras enceradas e montes e montes de cabieiros para chapéus e\ncasacos - o hobbit apreciava visitas." + }, + "row_qrcode": { + "qr_code": "code", + "intro": "Numa toca no chão vivia um hobbit. Não uma toca nojenta, suja, úmida, \ncheia de pontas de minhocas e um cheiro de limo, nem tam pouco uma toca seca, vazia, arenosa, \nsem nenhum lugar onde se sentar ou onde comer: era uma toca de hobbit, e isso significa conforto.\nEla tinha uma porta perfeitamente redonda feito uma escotilha, pintada de verde, com uma maçaneta\namarela e brilhante de latão exatamente no meio. A porta se abria para um corredor em forma de tubo,\nfeito um túnel: um túnel muito confortável, sem fumaça, de paredes com painéis e assoalhos\nazulejados e acarpetados, com cadeiras enceradas e montes e montes de cabieiros para chapéus e\ncasacos - o hobbit apreciava visitas." + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/auto_row_template.json b/test/maroto/processor/json/auto_row_template.json new file mode 100644 index 00000000..6edb07c9 --- /dev/null +++ b/test/maroto/processor/json/auto_row_template.json @@ -0,0 +1,132 @@ +{ + "builder":{ + "debug": true + }, + "pages": { + "page_template": { + "order": 1, + "row_with_larger_image": { + "order": 1, + "cols": [ + { + "image": { + "order": 1, + "source_key": "biplane" + }, + "size": 5 + }, + { + "text": { + "order": 1, + "source_key": "intro" + }, + "size": 7 + } + ] + }, + "row_with_image_and_text_same": { + "order": 2, + "cols": [ + { + "image": { + "order": 1, + "source_key": "biplane" + }, + "size": 5 + }, + { + "text": { + "order": 1, + "source_key": "intro", + "props": { + "size": 13 + } + }, + "size": 7 + } + ] + }, + "row_with_image2": { + "order": 3, + "cols": [ + { + "image": { + "order": 1, + "source_key": "biplane" + }, + "size": 5 + }, + { + "text": { + "order": 1, + "source_key": "intro", + "props": { + "size": 13, + "top": 8, + "bottom": 9 + } + }, + "size": 7 + } + ] + }, + "row_barcode": { + "order": 4, + "cols": [ + { + "bar_code": { + "order": 1, + "source_key": "bar_col" + }, + "size": 4 + }, + { + "text": { + "order": 1, + "source_key": "intro" + }, + "size": 8 + } + ] + }, + "row_matrixcode": { + "order": 5, + "cols": [ + { + "matrix_code": { + "order": 1, + "source_key": "matrix_code" + }, + "size": 3 + }, + { + "text": { + "order": 1, + "source_key": "intro" + }, + "size": 9 + } + ] + }, + "row_qrcode": { + "order": 6, + "cols": [ + { + "qr_code": { + "order": 1, + "source_key": "qr_code" + }, + "size": 2 + }, + { + "text": { + "order": 1, + "source_key": "intro" + }, + "size": 10 + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/background_content.json b/test/maroto/processor/json/background_content.json new file mode 100644 index 00000000..becfc152 --- /dev/null +++ b/test/maroto/processor/json/background_content.json @@ -0,0 +1,41 @@ +{ + "pages": { + "list_pages": [ + { + "page": { + "row_title": { + "title": "O GDG-Petrópolis certifica que Fulano de Tal 123 participou do Evento Exemplo 123 no dia 2019-03-30." + } + } + }, + { + "page": { + "row_title": { + "title": "O GDG-Petrópolis certifica que Fulano de Tal 123 participou do Evento Exemplo 123 no dia 2019-03-30." + } + } + }, + { + "page": { + "row_title": { + "title": "O GDG-Petrópolis certifica que Fulano de Tal 123 participou do Evento Exemplo 123 no dia 2019-03-30." + } + } + }, + { + "page": { + "row_title": { + "title": "O GDG-Petrópolis certifica que Fulano de Tal 123 participou do Evento Exemplo 123 no dia 2019-03-30." + } + } + }, + { + "page": { + "row_title": { + "title": "O GDG-Petrópolis certifica que Fulano de Tal 123 participou do Evento Exemplo 123 no dia 2019-03-30." + } + } + } + ] + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/background_template.json b/test/maroto/processor/json/background_template.json new file mode 100644 index 00000000..35e77026 --- /dev/null +++ b/test/maroto/processor/json/background_template.json @@ -0,0 +1,66 @@ +{ + "builder": { + "margins": { + "left": 0, + "top": 0, + "right": 0 + }, + "orientation": "horizontal", + "max_grid_size": 20, + "background_image": "docs/assets/images/certificate.png" + }, + "pages": { + "list_pages": { + "order": 1, + "page": { + "order": 1, + "row_space": { + "order": 1, + "height": 70 + }, + "row_title": { + "height": 20, + "order": 2, + "cols": [ + { + "size": 4 + }, + { + "size": 12, + "text": { + "order": 1, + "source_key": "title", + "props": { + "size": 18 + } + } + }, + { + "size": 4 + } + ] + }, + "row_space2": { + "order": 3, + "height": 15 + }, + "row_signature": { + "order": 4, + "height": 30, + "cols": [ + { + "size": 20, + "image": { + "order": 1, + "value": "docs/assets/images/signature.png", + "props": { + "center": true + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/barcodegrid_content.json b/test/maroto/processor/json/barcodegrid_content.json new file mode 100644 index 00000000..8999a02b --- /dev/null +++ b/test/maroto/processor/json/barcodegrid_content.json @@ -0,0 +1,24 @@ +{ + "pages": { + "template_page": { + "bar_code_row1": { + "maroto_url": "https://github.com/johnfercher/maroto" + }, + "bar_code_center_row1": { + "maroto_url": "https://github.com/johnfercher/maroto" + }, + "bar_code_row2": { + "maroto_url": "https://github.com/johnfercher/maroto" + }, + "bar_code_center_row2": { + "maroto_url": "https://github.com/johnfercher/maroto" + }, + "bar_code_EAN_row2": { + "code_number": "123456789123" + }, + "bar_code_auto_row": { + "code_number": "123456789123" + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/barcodegrid_template.json b/test/maroto/processor/json/barcodegrid_template.json new file mode 100644 index 00000000..6916a9d8 --- /dev/null +++ b/test/maroto/processor/json/barcodegrid_template.json @@ -0,0 +1,237 @@ +{ + "builder": { + "debug": true + }, + "pages": { + "template_page": { + "order": 1, + "bar_code_row1": { + "order": 1, + "height": 40, + "cols": [ + { + "size": 2, + "bar_code": { + "order": 1, + "source_key": "maroto_url", + "props": { + "percent": 50 + } + } + }, + { + "size": 4, + "bar_code": { + "order": 1, + "source_key": "maroto_url", + "props": { + "percent": 75 + } + } + }, + { + "size": 6, + "bar_code": { + "order": 1, + "source_key": "maroto_url", + "props": { + "percent": 100 + } + } + } + ] + }, + "bar_code_center_row1": { + "order": 2, + "height": 40, + "cols": [ + { + "size": 2, + "bar_code": { + "order": 1, + "source_key": "maroto_url", + "props": { + "center": true, + "percent": 50 + } + } + }, + { + "size": 4, + "bar_code": { + "order": 1, + "source_key": "maroto_url", + "props": { + "center": true, + "percent": 75 + } + } + }, + { + "size": 6, + "bar_code": { + "order": 1, + "source_key": "maroto_url", + "props": { + "center": true, + "percent": 100 + } + } + } + ] + }, + "bar_code_row2": { + "order": 3, + "height": 40, + "cols": [ + { + "size": 6, + "bar_code": { + "order": 1, + "source_key": "maroto_url", + "props": { + "percent": 50 + } + } + }, + { + "size": 4, + "bar_code": { + "order": 1, + "source_key": "maroto_url", + "props": { + "percent": 75 + } + } + }, + { + "size": 2, + "bar_code": { + "order": 1, + "source_key": "maroto_url", + "props": { + "percent": 100 + } + } + } + ] + }, + "bar_code_center_row2": { + "order": 4, + "height": 40, + "cols": [ + { + "size": 6, + "bar_code": { + "order": 1, + "source_key": "maroto_url", + "props": { + "center": true, + "percent": 50 + } + } + }, + { + "size": 4, + "bar_code": { + "order": 1, + "source_key": "maroto_url", + "props": { + "center": true, + "percent": 75 + } + } + }, + { + "size": 2, + "bar_code": { + "order": 1, + "source_key": "maroto_url", + "props": { + "center": true, + "percent": 100 + } + } + } + ] + }, + "bar_code_EAN_row2": { + "order": 5, + "height": 40, + "cols": [ + { + "size": 2, + "bar_code": { + "order": 1, + "source_key": "code_number", + "props": { + "center": true, + "type": "EAN" + } + } + }, + { + "size": 4, + "bar_code": { + "order": 1, + "source_key": "code_number", + "props": { + "center": true, + "type": "EAN" + } + } + }, + { + "size": 6, + "bar_code": { + "order": 1, + "source_key": "code_number", + "props": { + "center": true, + "type": "EAN" + } + } + } + ] + }, + "bar_code_auto_row": { + "order": 6, + "cols": [ + { + "size": 2, + "bar_code": { + "order": 1, + "source_key": "code_number", + "props": { + "center": true, + "type": "EAN" + } + } + }, + { + "size": 4, + "bar_code": { + "order": 1, + "source_key": "code_number", + "props": { + "center": true, + "type": "EAN" + } + } + }, + { + "size": 6, + "bar_code": { + "order": 1, + "source_key": "code_number", + "props": { + "center": true, + "type": "EAN" + } + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/billing_content.json b/test/maroto/processor/json/billing_content.json new file mode 100644 index 00000000..12b3597c --- /dev/null +++ b/test/maroto/processor/json/billing_content.json @@ -0,0 +1,194 @@ +{ + "header": { + "template_row": { + "biplane": "docs/assets/images/biplane.jpg", + "company_address": "AnyCompany Name Inc. 851 Any Street Name, Suite 120, Any City, CA 45123.", + "company_phone": "Tel: 55 024 12345-1234", + "company_site": "www.mycompany.com" + } + }, + "footer": { + "row_footer": { + "company_phone": "Tel: 55 024 12345-1234", + "company_site": "www.mycompany.com" + } + }, + "pages": { + "template_page": { + "invoice_row": { + "invoice": "Invoice ABC123456789" + }, + "list_transactions_row": [ + { + "transaction_gray": { + "product": "Swamp", + "quantity": "12", + "price": "R$ 4,00" + }, + "transaction_white": { + "product": "Sorin, A Planeswalker", + "quantity": "4", + "price": "R$ 90,00" + } + }, + { + "transaction_gray": { + "product": "Tassa", + "quantity": "4", + "price": "R$ 30,00" + }, + "transaction_white": { + "product": "Skinrender", + "quantity": "4", + "price": "R$ 9,00" + } + }, + { + "transaction_gray": { + "product": "Island", + "quantity": "12", + "price": "R$ 4,00" + }, + "transaction_white": { + "product": "Mountain", + "quantity": "12", + "price": "R$ 4,00" + } + }, + { + "transaction_gray": { + "product": "Plain", + "quantity": "12", + "price": "R$ 4,00" + }, + "transaction_white": { + "product": "Black Lotus", + "quantity": "1", + "price": "R$ 1.000,00" + } + }, + { + "transaction_gray": { + "product": "Time Walk", + "quantity": "1", + "price": "R$ 1.000,00" + }, + "transaction_white": { + "product": "Emberclave", + "quantity": "4", + "price": "R$ 44,00" + } + }, + { + "transaction_gray": { + "product": "Anax", + "quantity": "4", + "price": "R$ 32,00" + }, + "transaction_white": { + "product": "Murderous Rider", + "quantity": "4", + "price": "R$ 22,00" + } + }, + { + "transaction_gray": { + "product": "Gray Merchant of Asphodel", + "quantity": "4", + "price": "R$ 2,00" + }, + "transaction_white": { + "product": "Ajani's Pridemate", + "quantity": "4", + "price": "R$ 2,00" + } + }, + { + "transaction_gray": { + "product": "Renan, Chatuba", + "quantity": "4", + "price": "R$ 19,00" + }, + "transaction_white": { + "product": "Tymarett", + "quantity": "4", + "price": "R$ 13,00" + } + }, + { + "transaction_gray": { + "product": "Doom Blade", + "quantity": "4", + "price": "R$ 5,00" + }, + "transaction_white": { + "product": "Dark Lord", + "quantity": "3", + "price": "R$ 7,00" + } + }, + { + "transaction_gray": { + "product": "Memory of Thanatos", + "quantity": "3", + "price": "R$ 32,00" + }, + "transaction_white": { + "product": "Poring", + "quantity": "4", + "price": "R$ 1,00" + } + }, + { + "transaction_gray": { + "product": "Deviling", + "quantity": "4", + "price": "R$ 99,00" + }, + "transaction_white": { + "product": "Seiya", + "quantity": "4", + "price": "R$ 45,00" + } + }, + { + "transaction_gray": { + "product": "Harry Potter", + "quantity": "4", + "price": "R$ 62,00" + }, + "transaction_white": { + "product": "Goku", + "quantity": "4", + "price": "R$ 77,00" + } + }, + { + "transaction_gray": { + "product": "Phreoni", + "quantity": "4", + "price": "R$ 22,00" + }, + "transaction_white": { + "product": "Katheryn High Wizard", + "quantity": "4", + "price": "R$ 25,00" + } + }, + { + "transaction_gray": { + "product": "Lord Seyren", + "quantity": "4", + "price": "R$ 55,00" + } + } + ], + "total_row": { + "total": "R$ 2.567,00" + }, + "code_bar_row": { + "code": "5123.151231.512314.1251251.123215" + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/billing_template.json b/test/maroto/processor/json/billing_template.json new file mode 100644 index 00000000..7016fe1e --- /dev/null +++ b/test/maroto/processor/json/billing_template.json @@ -0,0 +1,380 @@ +{ + "builder": { + "margins": { + "left": 10, + "top": 15, + "right": 10 + }, + "page_number": {} + }, + "header": { + "template_row": { + "order": 1, + "height": 20, + "cols": [ + { + "size": 3, + "image": { + "order": 1, + "source_key": "biplane", + "props": { + "center": true, + "percent": 80 + } + } + }, + { + "size": 6 + }, + { + "size": 3, + "text_address": { + "order": 1, + "source_key": "company_address", + "props": { + "size": 8, + "align": "right", + "color": { + "red": 150, + "green": 10, + "blue": 10 + } + } + }, + "text_phone": { + "order": 2, + "source_key": "company_phone", + "props": { + "top": 12, + "style": "bold_italic", + "size": 8, + "align": "right", + "color": { + "red": 10, + "green": 10, + "blue": 150 + } + } + }, + "text_site": { + "order": 3, + "source_key": "company_site", + "props": { + "top": 15, + "style": "bold_italic", + "size": 8, + "align": "right", + "color": { + "red": 10, + "green": 10, + "blue": 150 + } + } + } + } + ] + } + }, + "footer": { + "row_footer": { + "order": 1, + "height": 20, + "cols": [ + { + "size": 12, + "text_phone": { + "order": 1, + "source_key": "company_phone", + "props": { + "top": 13, + "style": "bold_italic", + "size": 8, + "align": "left", + "color": { + "red": 10, + "green": 10, + "blue": 150 + } + } + }, + "text_site": { + "order": 2, + "source_key": "company_site", + "props": { + "top": 16, + "style": "bold_italic", + "size": 8, + "align": "left", + "color": { + "red": 10, + "green": 10, + "blue": 150 + } + } + } + } + ] + } + }, + "pages": { + "template_page": { + "order": 1, + "invoice_row": { + "order": 1, + "height": 10, + "cols": [ + { + "text": { + "order": 1, + "source_key": "invoice", + "props": { + "top": 3, + "style": "bold", + "align": "center" + } + } + } + ] + }, + "transactions_row": { + "order": 2, + "height": 7, + "props": { + "background_color": { + "red": 55, + "blue": 55, + "green": 55 + } + }, + "cols": [ + { + "size": 3, + "text": { + "order": 1, + "value": "Transactions", + "props": { + "top": 1.5, + "size": 9, + "style": "bold", + "align": "center", + "color": { + "red": 255, + "green": 255, + "blue": 255 + } + } + } + } + ] + }, + "transactions_header_row": { + "order": 3, + "height": 5, + "cols": [ + { + "size": 3 + }, + { + "size": 4, + "text": { + "order": 1, + "value": "Product", + "props": { + "size": 9, + "style": "bold", + "align": "center" + } + } + }, + { + "size": 2, + "text": { + "order": 1, + "value": "Quantity", + "props": { + "size": 9, + "style": "bold", + "align": "center" + } + } + }, + { + "size": 3, + "text": { + "order": 1, + "value": "Price", + "props": { + "size": 9, + "style": "bold", + "align": "center" + } + } + } + ] + }, + "list_transactions_row": { + "order": 4, + "transaction_gray": { + "order": 1, + "height": 4, + "props": { + "background_color": { + "red": 200, + "green": 200, + "blue": 200 + } + }, + "cols": [ + { + "size": 3 + }, + { + "size": 4, + "text": { + "order": 1, + "source_key": "product", + "props": { + "size": 8, + "align": "center" + } + } + }, + { + "size": 2, + "text": { + "order": 1, + "source_key": "quantity", + "props": { + "size": 8, + "align": "center" + } + } + }, + { + "size": 3, + "text": { + "order": 1, + "source_key": "price", + "props": { + "size": 8, + "align": "center" + } + } + } + ] + }, + "transaction_white": { + "order": 2, + "height": 4, + "cols": [ + { + "size": 3 + }, + { + "size": 4, + "text": { + "order": 1, + "source_key": "product", + "props": { + "size": 8, + "align": "center" + } + } + }, + { + "size": 2, + "text": { + "order": 1, + "source_key": "quantity", + "props": { + "size": 8, + "align": "center" + } + } + }, + { + "size": 3, + "text": { + "order": 1, + "source_key": "price", + "props": { + "size": 8, + "align": "center" + } + } + } + ] + } + }, + "total_row": { + "order": 5, + "height": 20, + "cols": [ + { + "size": 7 + }, + { + "size": 2, + "text": { + "order": 1, + "value": "Total:", + "props": { + "top": 5, + "style": "bold", + "size": 8, + "align": "right" + } + } + }, + { + "size": 3, + "text": { + "order": 1, + "source_key": "total", + "props": { + "top": 5, + "style": "bold", + "size": 8, + "align": "center" + } + } + } + ] + }, + "code_bar_row": { + "order": 6, + "height": 15, + "cols": [ + { + "size": 6, + "bar_code":{ + "order": 1, + "source_key": "code", + "props": { + "proportion": { + "width": 20, + "height": 2 + }, + "percent": 100 + } + }, + "text": { + "order": 2, + "source_key": "code", + "props": { + "top": 12, + "family": "", + "style": "bold", + "size": 9, + "align": "center" + } + } + }, + { + "size": 6 + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/cell_template.json b/test/maroto/processor/json/cell_template.json new file mode 100644 index 00000000..10e54bb6 --- /dev/null +++ b/test/maroto/processor/json/cell_template.json @@ -0,0 +1,2578 @@ +{ + "builder": { + "debug": false + }, + "pages": { + "template_page": { + "order": 1, + "default_style_row_1": { + "order": 1, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_1": { + "order": 2, + "height": 10 + }, + "template_row_1": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "none" + + }, + "order": 3, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_2": { + "order": 4, + "height": 10 + }, + "default_style_row_2": { + "order": 5, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_3": { + "order": 6, + "height": 10 + }, + "template_row_2": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "full" + }, + "order": 7, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_4": { + "order": 8, + "height": 10 + }, + "default_style_row_3": { + "order": 9, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_5": { + "order": 10, + "height": 10 + }, + "template_row_3": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "left" + }, + "order": 11, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_6": { + "order": 12, + "height": 10 + }, + "default_style_row_4": { + "order": 13, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_7": { + "order": 14, + "height": 10 + }, + "template_row_4": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "right" + }, + "order": 15, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_8": { + "order": 16, + "height": 10 + }, + "default_style_row_5": { + "order": 17, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_9": { + "order": 18, + "height": 10 + }, + "template_row_5": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "top" + }, + "order": 19, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_10": { + "order": 20, + "height": 10 + }, + "default_style_row_6": { + "order": 21, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_11": { + "order": 22, + "height": 10 + }, + "template_row_6": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "bottom" + }, + "order": 23, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_12": { + "order": 24, + "height": 10 + }, + "default_style_row_7": { + "order": 25, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_13": { + "order": 26, + "height": 10 + }, + "template_row_7": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "none" + + }, + "order": 27, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_14": { + "order": 28, + "height": 10 + }, + "default_style_row_8": { + "order": 29, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_15": { + "order": 30, + "height": 10 + }, + "template_row_8": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "full" + }, + "order": 31, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_16": { + "order": 32, + "height": 10 + }, + "default_style_row_9": { + "order": 33, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_17": { + "order": 34, + "height": 10 + }, + "template_row_9": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "left" + }, + "order": 35, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_18": { + "order": 36, + "height": 10 + }, + "default_style_row_10": { + "order": 37, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_19": { + "order": 38, + "height": 10 + }, + "template_row_10": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "right" + }, + "order": 39, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_20": { + "order": 40, + "height": 10 + }, + "default_style_row_11": { + "order": 41, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_21": { + "order": 42, + "height": 10 + }, + "template_row_11": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "top" + }, + "order": 43, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_22": { + "order": 44, + "height": 10 + }, + "default_style_row_12": { + "order": 45, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_23": { + "order": 46, + "height": 10 + }, + "template_row_12": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "bottom" + }, + "order": 47, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_24": { + "order": 48, + "height": 10 + }, + "default_style_row_13": { + "order": 49, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_25": { + "order": 50, + "height": 10 + }, + "template_row_13": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "none" + + }, + "order": 51, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_26": { + "order": 52, + "height": 10 + }, + "default_style_row_14": { + "order": 53, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_27": { + "order": 54, + "height": 10 + }, + "template_row_14": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "full" + }, + "order": 55, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_28": { + "order": 56, + "height": 10 + }, + "default_style_row_15": { + "order": 57, + "height": 10, + "cols": [ + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "props": { + "background_color": { + "red": 80, + "green": 80, + "blue": 80 + }, + "border_type": "full", + "border_color": { + "red": 200, + "green": 0, + "blue": 0 + }, + "line_style": "dashed", + "border_thickness": 0.5 + }, + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "color": { + "red": 255, + "green": 255, + "blue": 255 + }, + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_29": { + "order": 58, + "height": 10 + }, + "template_row_15": { + "props": { + "background_color": { + "red": 220, + "green": 220, + "blue": 220 + }, + "border_color": { + "red": 0, + "green": 0, + "blue": 200 + }, + "border_type": "left" + }, + "order": 59, + "height": 10, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "string", + "props": { + "style": "bold", + "size": 12, + "align": "center", + "top": 2 + } + } + } + ] + }, + "space_row_30": { + "order": 60, + "height": 10 + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/compressionv2_template.json b/test/maroto/processor/json/compressionv2_template.json new file mode 100644 index 00000000..8f34c85a --- /dev/null +++ b/test/maroto/processor/json/compressionv2_template.json @@ -0,0 +1,229 @@ +{ + "builder": { + "compression": true + }, + "pages": { + "template_page": { + "order": 1, + "title_row": { + "order": 1, + "height": 20, + "cols": [ + { + "text": { + "order": 1, + "value": "Main features", + "props": { + "size": 15, + "top": 6.5 + } + } + } + ] + }, + "barcode_row": { + "order": 2, + "height": 20, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "Barcode:", + "props": { + "size": 15, + "top": 6, + "align": "center" + } + } + }, + { + "size": 8, + "bar_code": { + "order": 1, + "value": "barcode", + "props": { + "center": true, + "percent": 70 + } + } + } + ] + }, + "qrcode_row": { + "order": 3, + "height": 20, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "QrCode:", + "props": { + "size": 15, + "top": 6, + "align": "center" + } + } + }, + { + "size": 8, + "qr_code": { + "order": 1, + "value": "qrcode", + "props": { + "center": true, + "percent": 70 + } + } + } + ] + }, + "matrixcode_row": { + "order": 4, + "height": 20, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "MatrixCode:", + "props": { + "size": 15, + "top": 6, + "align": "center" + } + } + }, + { + "size": 8, + "matrix_code": { + "order": 1, + "value": "matrixcode", + "props": { + "center": true, + "percent": 70 + } + } + } + ] + }, + "image_file_row": { + "order": 5, + "height": 20, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "Image From File:", + "props": { + "size": 15, + "top": 6, + "align": "center" + } + } + }, + { + "size": 8, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg", + "props": { + "center": true, + "percent": 90 + } + } + } + ] + }, + "image_base64_row": { + "order": 6, + "height": 20, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "Image From Base64::", + "props": { + "size": 15, + "top": 6, + "align": "center" + } + } + }, + { + "size": 8, + "image": { + "order": 1, + "value": "https://github.com/johnfercher/maroto/blob/master/docs/assets/images/frontpage.png?raw=true", + "props": { + "center": true, + "percent": 90 + } + } + } + ] + }, + "text_row": { + "order": 7, + "height": 20, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "Text:", + "props": { + "size": 15, + "top": 6, + "align": "center" + } + } + }, + { + "size": 8, + "text": { + "order": 1, + "value": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ac condimentum sem.", + "props": { + "size": 12, + "top": 5, + "align": "center" + } + } + } + ] + }, + "signature_row": { + "order": 8, + "height": 40, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "value": "Signature:", + "props": { + "size": 15, + "top": 17, + "align": "center" + } + } + }, + { + "size": 8, + "signature": { + "order": 1, + "value": "Name", + "props": { + "font_size": 10 + } + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/customdimensions_template.json b/test/maroto/processor/json/customdimensions_template.json new file mode 100644 index 00000000..e6f5885b --- /dev/null +++ b/test/maroto/processor/json/customdimensions_template.json @@ -0,0 +1,45 @@ +{ + "builder": { + "debug": true, + "dimensions": { + "width": 200, + "height": 200 + } + }, + "pages": { + "template_page": { + "order": 1, + "template_row": { + "height": 40, + "order": 1, + "cols": [ + { + "size": 4, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg", + "props": { + "center": true, + "percent": 50 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "Gopher International Shipping, Inc.", + "props": { + "top": 12, + "size": 12 + } + } + }, + { + "size": 4 + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/customfont_content.json b/test/maroto/processor/json/customfont_content.json new file mode 100644 index 00000000..cb74775d --- /dev/null +++ b/test/maroto/processor/json/customfont_content.json @@ -0,0 +1,561 @@ +{ + "pages": { + "template_page": { + "template_header_row": { + "column_1": "Language", + "column_2": "Phrase: Talk is cheap. Show me the code." + }, + "list_languages": [ + { + "template_white_row": { + "content_column_1": "Albanês", + "content_column_2": "Biseda është e lirë. Më trego kodin." + }, + "template_white_gray": { + "content_column_1": "Africâner", + "content_column_2": "Praat is goedkoop. Wys my die kode." + } + }, + { + "template_white_row": { + "content_column_1": "Amárico", + "content_column_2": "ወሬ ርካሽ ነው ፡፡ ኮዱን አሳዩኝ ፡፡" + }, + "template_white_gray": { + "content_column_1": "Alemão", + "content_column_2": "Reden ist billig. Zeig mir den Code." + } + }, + { + "template_white_row": { + "content_column_1": "Armênio", + "content_column_2": "Խոսակցությունն էժան է: Showույց տվեք ինձ ծածկագիրը:" + }, + "template_white_gray": { + "content_column_1": "Árabe", + "content_column_2": "كلام رخيص. أرني الكود." + } + }, + { + "template_white_row": { + "content_column_1": "Basco", + "content_column_2": "Eztabaida merkea da. Erakutsi kodea." + }, + "template_white_gray": { + "content_column_1": "Azerbaijano", + "content_column_2": "Danışıq ucuzdur. Kodu göstərin." + } + }, + { + "template_white_row": { + "content_column_1": "Bielorusso", + "content_column_2": "Размовы танныя. Пакажыце мне код." + }, + "template_white_gray": { + "content_column_1": "Bengali", + "content_column_2": "টক সস্তা। আমাকে কোডটি দেখান" + } + }, + { + "template_white_row": { + "content_column_1": "Bósnio", + "content_column_2": "Govor je jeftin. Pokaži mi šifru." + }, + "template_white_gray": { + "content_column_1": "Birmanês", + "content_column_2": "ဟောပြောချက်ကစျေးပေါတယ် ကုဒ်ကိုပြပါ။" + } + }, + { + "template_white_row": { + "content_column_1": "Canarim", + "content_column_2": "ಮಾತುಕತೆ ಅಗ್ಗವಾಗಿದೆ. ನನಗೆ ಕೋಡ್ ತೋರಿಸಿ." + }, + "template_white_gray": { + "content_column_1": "Búlgaro", + "content_column_2": "Разговорите са евтини. Покажи ми кода." + } + }, + { + "template_white_row": { + "content_column_1": "Cazeque", + "content_column_2": "Сөйлесу арзан. Маған кодты көрсетіңіз." + }, + "template_white_gray": { + "content_column_1": "Catalão", + "content_column_2": "Parlar és barat. Mostra’m el codi." + } + }, + { + "template_white_row": { + "content_column_1": "Chinês Simplificado", + "content_column_2": "谈话很便宜。给我看代码。" + }, + "template_white_gray": { + "content_column_1": "Cebuano", + "content_column_2": "Barato ra ang sulti. Ipakita kanako ang code." + } + }, + { + "template_white_row": { + "content_column_1": "Cingalês", + "content_column_2": "කතාව ලාභයි. කේතය මට පෙන්වන්න." + }, + "template_white_gray": { + "content_column_1": "Chinês Tradicional", + "content_column_2": "談話很便宜。給我看代碼。" + } + }, + { + "template_white_row": { + "content_column_1": "Corso", + "content_column_2": "Parlà hè bonu. Mostrami u codice." + }, + "template_white_gray": { + "content_column_1": "Coreano", + "content_column_2": "토크는 싸다. 코드를 보여주세요." + } + }, + { + "template_white_row": { + "content_column_1": "Curdo", + "content_column_2": "Axaftin erzan e. Kodê nîşanî min bidin." + }, + "template_white_gray": { + "content_column_1": "Croata", + "content_column_2": "Razgovor je jeftin. Pokaži mi šifru." + } + }, + { + "template_white_row": { + "content_column_1": "Eslovaco", + "content_column_2": "Hovor je lacný. Ukáž mi kód." + }, + "template_white_gray": { + "content_column_1": "Dinamarquês", + "content_column_2": "Tal er billig. Vis mig koden." + } + }, + { + "template_white_gray": { + "content_column_1": "Esloveno", + "content_column_2": "Pogovor je poceni. Pokaži mi kodo." + }, + "template_white_row": { + "content_column_1": "Espanhol", + "content_column_2": "Hablar es barato. Enséñame el código." + } + }, + { + "template_white_gray": { + "content_column_1": "Esperanto", + "content_column_2": "Babilado estas malmultekosta. Montru al mi la kodon." + }, + "template_white_row": { + "content_column_1": "Estoniano", + "content_column_2": "Rääkimine on odav. Näita mulle koodi." + } + }, + { + "template_white_gray": { + "content_column_1": "Filipino", + "content_column_2": "Mura ang usapan. Ipakita sa akin ang code." + }, + "template_white_row": { + "content_column_1": "Finlandês", + "content_column_2": "Puhe on halpaa. Näytä koodi." + } + }, + { + "template_white_gray": { + "content_column_1": "Francês", + "content_column_2": "Parler n'est pas cher. Montre-moi le code." + }, + "template_white_row": { + "content_column_1": "Frísio Ocidental", + "content_column_2": "Prate is goedkeap. Lit my de koade sjen." + } + }, + { + "template_white_gray": { + "content_column_1": "Gaélico Escocês", + "content_column_2": "Tha còmhradh saor. Seall dhomh an còd." + }, + "template_white_row": { + "content_column_1": "Galego", + "content_column_2": "Falar é barato. Móstrame o código." + } + }, + { + "template_white_gray": { + "content_column_1": "Galês", + "content_column_2": "Mae siarad yn rhad. Dangoswch y cod i mi." + }, + "template_white_row": { + "content_column_1": "Georgiano", + "content_column_2": "აუბარი იაფია. მაჩვენე კოდი." + } + }, + { + "template_white_gray": { + "content_column_1": "Grego", + "content_column_2": "Η συζήτηση είναι φθηνή. Δείξε μου τον κωδικό." + }, + "template_white_row": { + "content_column_1": "Guzerate", + "content_column_2": "વાતો કરવી સસ્તી છે. મને કોડ બતાવો." + } + }, + { + "template_white_gray": { + "content_column_1": "Haitiano", + "content_column_2": "Pale bon mache. Montre m kòd la." + }, + "template_white_row": { + "content_column_1": "Hauçá", + "content_column_2": "Magana tana da arha. Nuna min lambar." + } + }, + { + "template_white_gray": { + "content_column_1": "Havaiano", + "content_column_2": "Kūʻai ke kamaʻilio. E hōʻike mai iaʻu i ke pāʻālua." + }, + "template_white_row": { + "content_column_1": "Hebraico", + "content_column_2": "הדיבורים זולים. הראה לי את הקוד." + } + }, + { + "template_white_gray": { + "content_column_1": "Híndi", + "content_column_2": "बोलना आसान है। मुझे कोड दिखाओ।" + }, + "template_white_row": { + "content_column_1": "Hmong", + "content_column_2": "Kev hais lus yog pheej yig. Qhia kuv cov code." + } + }, + { + "template_white_gray": { + "content_column_1": "Holandês", + "content_column_2": "Praten is goedkoop. Laat me de code zien." + }, + "template_white_row": { + "content_column_1": "Húngaro", + "content_column_2": "Beszélni olcsó. Mutasd meg a kódot." + } + }, + { + "template_white_gray": { + "content_column_1": "Igbo", + "content_column_2": "Okwu dị ọnụ ala. Gosi m koodu." + }, + "template_white_row": { + "content_column_1": "Lídiche", + "content_column_2": "רעדן איז ביליק. ווייַזן מיר דעם קאָד." + } + }, + { + "template_white_gray": { + "content_column_1": "Indonésio", + "content_column_2": "Berbicara itu murah. Tunjukkan kodenya." + }, + "template_white_row": { + "content_column_1": "Inglês", + "content_column_2": "Talk is cheap. Show me the code." + } + }, + { + "template_white_gray": { + "content_column_1": "Iorubá", + "content_column_2": "Ọrọ jẹ olowo poku. Fi koodu naa han mi." + }, + "template_white_row": { + "content_column_1": "Irlandês", + "content_column_2": "Tá caint saor. Taispeáin dom an cód." + } + }, + { + "template_white_gray": { + "content_column_1": "Islandês", + "content_column_2": "Tal er ódýrt. Sýndu mér kóðann." + }, + "template_white_row": { + "content_column_1": "Italiano", + "content_column_2": "Parlare è economico. Mostrami il codice." + } + }, + { + "template_white_gray": { + "content_column_1": "Japonês", + "content_column_2": "口で言うだけなら簡単です。コードを見せてください。" + }, + "template_white_row": { + "content_column_1": "Javanês", + "content_column_2": "Omongan iku murah. Tampilake kode kasebut." + } + }, + { + "template_white_gray": { + "content_column_1": "Khmer", + "content_column_2": "ការនិយាយគឺថោក។ បង្ហាញលេខកូដមកខ្ញុំ" + }, + "template_white_row": { + "content_column_1": "Laosiano", + "content_column_2": "ການສົນທະນາແມ່ນລາຄາຖືກ. ສະແດງລະຫັດໃຫ້ຂ້ອຍ." + } + }, + { + "template_white_gray": { + "content_column_1": "Latim", + "content_column_2": "Disputatio vilis est. Ostende mihi codice." + }, + "template_white_row": { + "content_column_1": "Letão", + "content_column_2": "Saruna ir lēta. Parādiet man kodu." + } + }, + { + "template_white_gray": { + "content_column_1": "Lituano", + "content_column_2": "Kalbėti pigu. Parodyk man kodą." + }, + "template_white_row": { + "content_column_1": "Luxemburguês", + "content_column_2": "Schwätzen ass bëlleg. Weist mir de Code." + } + }, + { + "template_white_gray": { + "content_column_1": "Macedônio", + "content_column_2": "Зборувањето е ефтино. Покажи ми го кодот." + }, + "template_white_row": { + "content_column_1": "Malaiala", + "content_column_2": "സംസാരം വിലകുറഞ്ഞതാണ്. എനിക്ക് കോഡ് കാണിക്കുക." + } + }, + { + "template_white_gray": { + "content_column_1": "Malaio", + "content_column_2": "Perbincangan murah. Tunjukkan kod saya." + }, + "template_white_row": { + "content_column_1": "Malgaxe", + "content_column_2": "Mora ny resaka. Asehoy ahy ny kaody." + } + }, + { + "template_white_gray": { + "content_column_1": "Maltês", + "content_column_2": "It-taħdita hija rħisa. Urini l-kodiċi." + }, + "template_white_row": { + "content_column_1": "Maori", + "content_column_2": "He iti te korero. Whakaatuhia mai te tohu." + } + }, + { + "template_white_gray": { + "content_column_1": "Marati", + "content_column_2": "चर्चा स्वस्त आहे. मला कोड दाखवा." + }, + "template_white_row": { + "content_column_1": "Mongol", + "content_column_2": "Яриа хямд. Надад кодоо харуул." + } + }, + { + "template_white_gray": { + "content_column_1": "Nepalês", + "content_column_2": "कुरा सस्तो छ। मलाई कोड देखाउनुहोस्।" + }, + "template_white_row": { + "content_column_1": "Nianja", + "content_column_2": "Kulankhula ndikotsika mtengo. Ndiwonetseni nambala" + } + }, + { + "template_white_gray": { + "content_column_1": "Norueguês", + "content_column_2": "Snakk er billig. Vis meg koden." + }, + "template_white_row": { + "content_column_1": "Oriá", + "content_column_2": "କଥାବାର୍ତ୍ତା ଶସ୍ତା ଅଟେ | ମୋତେ କୋଡ୍ ଦେଖାନ୍ତୁ |" + } + }, + { + "template_white_gray": { + "content_column_1": "Panjabi", + "content_column_2": "ਗੱਲ ਸਸਤਾ ਹੈ. ਮੈਨੂੰ ਕੋਡ ਦਿਖਾਓ." + }, + "template_white_row": { + "content_column_1": "Pashto", + "content_column_2": "خبرې ارزانه دي. ما ته کوډ وښایاست" + } + }, + { + "template_white_gray": { + "content_column_1": "Persa", + "content_column_2": "بحث ارزان است. کد را به من نشان دهید" + }, + "template_white_row": { + "content_column_1": "Polonês", + "content_column_2": "Rozmowa jest tania. Pokaż mi kod." + } + }, + { + "template_white_gray": { + "content_column_1": "Português", + "content_column_2": "Falar é fácil. Mostre-me o código." + }, + "template_white_row": { + "content_column_1": "Quiniaruanda", + "content_column_2": "Ibiganiro birahendutse. Nyereka kode." + } + }, + { + "template_white_gray": { + "content_column_1": "Quirguiz", + "content_column_2": "Сүйлөшүү арзан. Мага кодду көрсөтүңүз." + }, + "template_white_row": { + "content_column_1": "Romeno", + "content_column_2": "Vorbirea este ieftină. Arată-mi codul." + } + }, + { + "template_white_gray": { + "content_column_1": "Russo", + "content_column_2": "Обсуждение дешево. Покажи мне код." + }, + "template_white_row": { + "content_column_1": "Samoano", + "content_column_2": "E taugofie talanoaga. Faʻaali mai le code." + } + }, + { + "template_white_gray": { + "content_column_1": "Sérvio", + "content_column_2": "Причање је јефтино. Покажи ми шифру." + }, + "template_white_row": { + "content_column_1": "Sindi", + "content_column_2": "ڳالهه سستا آهي. مونکي ڪوڊ ڏيکاريو." + } + }, + { + "template_white_gray": { + "content_column_1": "Somali", + "content_column_2": "Hadalku waa jaban yahay. I tus lambarka." + }, + "template_white_row": { + "content_column_1": "Soto do Sul", + "content_column_2": "Puo e theko e tlase. Mpontshe khoutu." + } + }, + { + "template_white_gray": { + "content_column_1": "Suaíli", + "content_column_2": "Mazungumzo ni ya bei rahisi. Nionyeshe nambari." + }, + "template_white_row": { + "content_column_1": "Sueco", + "content_column_2": "Prat är billigt. Visa mig koden." + } + }, + { + "template_white_gray": { + "content_column_1": "Sundanês", + "content_column_2": "Omongan mirah. Tunjukkeun kode na." + }, + "template_white_row": { + "content_column_1": "Tadjique", + "content_column_2": "Сӯҳбат арзон аст. Рамзро ба ман нишон диҳед." + } + }, + { + "template_white_gray": { + "content_column_1": "Tailandês", + "content_column_2": "พูดคุยราคาถูก แสดงรหัส" + }, + "template_white_row": { + "content_column_1": "Tâmil", + "content_column_2": "பேச்சு மலிவானது. குறியீட்டை எனக்குக் காட்டு." + } + }, + { + "template_white_gray": { + "content_column_1": "Tártaro", + "content_column_2": "Сөйләшү арзан. Миңа код күрсәтегез." + }, + "template_white_row": { + "content_column_1": "Tcheco", + "content_column_2": "Mluvení je levné. Ukaž mi kód." + } + }, + { + "template_white_gray": { + "content_column_1": "Télugo", + "content_column_2": "చర్చ చౌకగా ఉంటుంది. నాకు కోడ్ చూపించు." + }, + "template_white_row": { + "content_column_1": "Turco", + "content_column_2": "Konuşma ucuz. Bana kodu göster." + } + }, + { + "template_white_gray": { + "content_column_1": "Turcomeno", + "content_column_2": "Gepleşik arzan. Kody görkez" + }, + "template_white_row": { + "content_column_1": "Ucraniano", + "content_column_2": "Розмова дешева. Покажи мені код." + } + }, + { + "template_white_gray": { + "content_column_1": "Uigur", + "content_column_2": "پاراڭ ئەرزان. ماڭا كودنى كۆرسەت." + }, + "template_white_row": { + "content_column_1": "Urdu", + "content_column_2": "بات گھٹیا ہے. مجھے کوڈ دکھائیں۔" + } + }, + { + "template_white_gray": { + "content_column_1": "Uzbeque", + "content_column_2": "Gapirish arzon. Menga kodni ko'rsating." + }, + "template_white_row": { + "content_column_1": "Vietnamita", + "content_column_2": "Nói chuyện là rẻ. Cho tôi xem mã." + } + }, + { + "template_white_gray": { + "content_column_1": "Xhosa", + "content_column_2": "Ukuthetha akubizi. Ndibonise ikhowudi." + }, + "template_white_row": { + "content_column_1": "Xona", + "content_column_2": "Kutaura kwakachipa. Ndiratidze kodhi." + } + }, + { + "template_white_gray": { + "content_column_1": "Zulu", + "content_column_2": "Ukukhuluma kushibhile. Ngikhombise ikhodi." + } + } + ], + "template_long_text_row": { + "long_text": "聲音之道㣲矣天地有自然之聲人聲有自然之節古之聖人得其節之自然者而為之依永和聲至於八音諧而神人和胥是道也文字之作無不講求音韻顧南北異其風土古今殊其轉變喉舌唇齒清濁輕重之分辨在毫釐動多訛舛樊然淆混不可究極自西域梵僧定字母為三十六分五音以總天下之聲而翻切之學興儒者若司馬光鄭樵皆宗之其法有音和類隔互用借聲類例不一後人苦其委曲繁重難以驟曉往往以類隔互用之切改從音和而終莫能得其原也我聖祖仁皇帝" + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/customfont_template.json b/test/maroto/processor/json/customfont_template.json new file mode 100644 index 00000000..80bca525 --- /dev/null +++ b/test/maroto/processor/json/customfont_template.json @@ -0,0 +1,183 @@ +{ + "builder": { + "custom_fonts": [ + { + "family": "arial-unicode-ms", + "style": "", + "file_path": "docs/assets/fonts/arial-unicode-ms.ttf" + }, + { + "family": "arial-unicode-ms", + "style": "italic", + "file_path": "docs/assets/fonts/arial-unicode-ms.ttf" + }, + { + "family": "arial-unicode-ms", + "style": "bold", + "file_path": "docs/assets/fonts/arial-unicode-ms.ttf" + }, + { + "family": "arial-unicode-ms", + "style": "bold_italic", + "file_path": "docs/assets/fonts/arial-unicode-ms.ttf" + } + ], + "default_font": { + "family": "arial-unicode-ms" + } + }, + "pages": { + "template_page": { + "order": 1, + "template_header_row": { + "order": 1, + "height": 8, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "props": { + "style": "bold", + "family": "arial", + "align": "center" + }, + "source_key": "column_1" + } + }, + { + "size": 8, + "text": { + "order": 1, + "props": { + "style": "bold", + "family": "arial", + "align": "center" + }, + "source_key": "column_2" + } + } + ] + }, + "list_languages": { + "order": 2, + "template_white_gray": { + "height": 5, + "order": 1, + "props": { + "background_color": { + "red": 200, + "green": 200, + "blue": 200 + } + }, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "source_key": "content_column_1", + "props": { + "align": "center" + } + } + }, + { + "size": 8, + "text": { + "order": 1, + "source_key": "content_column_2", + "props": { + "align": "center" + } + } + } + ] + }, + "template_white_row": { + "height": 5, + "order": 2, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "source_key": "content_column_1", + "props": { + "align": "center" + } + } + }, + { + "size": 8, + "text": { + "order": 1, + "source_key": "content_column_2", + "props": { + "align": "center" + } + } + } + ] + } + }, + "template_long_text_title_row": { + "order": 3, + "height": 10, + "cols": [ + { + "text": { + "order": 1, + "value": "long text without spaces", + "props": { + "top": 5, + "style": "bold", + "family": "arial" + } + } + } + ] + }, + "template_long_text_row": { + "order": 4, + "height": 80, + "cols": [ + { + "size": 4, + "text": { + "order": 1, + "source_key": "long_text", + "props": { + "align": "center", + "break_line_strategy": "dash_strategy" + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "source_key": "long_text", + "props": { + "align": "left", + "break_line_strategy": "dash_strategy" + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "source_key": "long_text", + "props": { + "align": "right", + "break_line_strategy": "dash_strategy" + } + } + } + ] + } + + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/custompage_template.json b/test/maroto/processor/json/custompage_template.json new file mode 100644 index 00000000..bd614826 --- /dev/null +++ b/test/maroto/processor/json/custompage_template.json @@ -0,0 +1,42 @@ +{ + "builder": { + "debug": true, + "page_size": "a2" + }, + "pages": { + "template_page": { + "order": 1, + "template_row": { + "order": 1, + "height": 40, + "cols": [ + { + "size": 4, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg", + "props": { + "center": true, + "percent": 50 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "Gopher International Shipping, Inc.", + "props": { + "top": 12, + "size": 12 + } + } + }, + { + "size": 4 + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/datamatrixgrid_template.json b/test/maroto/processor/json/datamatrixgrid_template.json new file mode 100644 index 00000000..eaafcc90 --- /dev/null +++ b/test/maroto/processor/json/datamatrixgrid_template.json @@ -0,0 +1,201 @@ +{ + "builder": { + "debug": true + }, + "pages": { + "template_page": { + "order": 1, + "matrixcode_row": { + "order": 1, + "height": 40, + "cols": [ + { + "size": 2, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 50 + } + } + }, + { + "size": 4, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 75 + } + } + }, + { + "size": 6, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 100 + } + } + } + ] + }, + "matrixcode_center_row": { + "order": 2, + "height": 40, + "cols": [ + { + "size": 2, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 50, + "center": true + } + } + }, + { + "size": 4, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 75, + "center": true + } + } + }, + { + "size": 6, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 100, + "center": true + } + } + } + ] + }, + "inverse_matrixcode_row": { + "order": 3, + "height": 40, + "cols": [ + { + "size": 6, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 50 + } + } + }, + { + "size": 4, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 75 + } + } + }, + { + "size": 2, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 100 + } + } + } + ] + }, + "inverse_matrixcode_center_row": { + "order": 4, + "height": 40, + "cols": [ + { + "size": 6, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 50, + "center": true + } + } + }, + { + "size": 4, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 75, + "center": true + } + } + }, + { + "size": 2, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 100, + "center": true + } + } + } + ] + }, + "matrixcode_autorow": { + "order": 5, + "cols": [ + { + "size": 6, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 20, + "center": true, + "just_reference_width": true + } + } + }, + { + "size": 4, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 75, + "center": true, + "just_reference_width": true + } + } + }, + { + "size": 2, + "matrix_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 100, + "center": true, + "just_reference_width": true + } + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/disablepagebreak_template.json b/test/maroto/processor/json/disablepagebreak_template.json new file mode 100644 index 00000000..1d646851 --- /dev/null +++ b/test/maroto/processor/json/disablepagebreak_template.json @@ -0,0 +1,23 @@ +{ + "builder": { + "margins": { + "top": 0, + "right": 0, + "left": 0, + "bottom": 0 + }, + "dimensions": { + "width": 361.8, + "height": 203.2 + }, + "disable_auto_page_break": true, + "orientation": "horizontal", + "max_grid_size": 20, + "background_image": "docs/assets/images/certificate.png" + }, + "pages": { + "template_page": { + "order": 1 + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/footer_content.json b/test/maroto/processor/json/footer_content.json new file mode 100644 index 00000000..a25ab2b3 --- /dev/null +++ b/test/maroto/processor/json/footer_content.json @@ -0,0 +1,258 @@ +{ + "pages": { + "template_page": { + "list_rows": [ + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + } + ] + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/footer_template.json b/test/maroto/processor/json/footer_template.json new file mode 100644 index 00000000..6554d7ef --- /dev/null +++ b/test/maroto/processor/json/footer_template.json @@ -0,0 +1,47 @@ +{ + "builder": { + "debug": true + }, + "footer": { + "template_row": { + "order": 1, + "height": 20, + "cols": [ + { + "text": { + "order": 1, + "value": "Footer", + "props": { + "size": 10, + "style": "bold", + "align": "center" + } + } + } + ] + } + }, + "pages": { + "template_page": { + "order": 1, + "list_rows": { + "order": 1, + "template_row": { + "order": 1, + "height": 10, + "cols": [ + { + "text": { + "order": 1, + "source_key": "text_value", + "props": { + "size": 8 + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/header_content.json b/test/maroto/processor/json/header_content.json new file mode 100644 index 00000000..a25ab2b3 --- /dev/null +++ b/test/maroto/processor/json/header_content.json @@ -0,0 +1,258 @@ +{ + "pages": { + "template_page": { + "list_rows": [ + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + } + ] + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/header_template.json b/test/maroto/processor/json/header_template.json new file mode 100644 index 00000000..66033c06 --- /dev/null +++ b/test/maroto/processor/json/header_template.json @@ -0,0 +1,47 @@ +{ + "builder": { + "debug": true + }, + "header": { + "template_row": { + "order": 1, + "height": 20, + "cols": [ + { + "text": { + "order": 1, + "value": "Header", + "props": { + "size": 10, + "style": "bold", + "align": "center" + } + } + } + ] + } + }, + "pages": { + "template_page": { + "order": 1, + "list_rows": { + "order": 1, + "template_row": { + "order": 1, + "height": 10, + "cols": [ + { + "text": { + "order": 1, + "source_key": "text_value", + "props": { + "size": 8 + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/imagegrid_template.json b/test/maroto/processor/json/imagegrid_template.json new file mode 100644 index 00000000..05d2e347 --- /dev/null +++ b/test/maroto/processor/json/imagegrid_template.json @@ -0,0 +1,304 @@ +{ + "builder": { + "debug": true + }, + "pages": { + "template_page": { + "order": 1, + "template_row1": { + "order": 1, + "height": 40, + "cols": [ + { + "size": 2, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg", + "props": { + "center": true, + "percent": 80 + } + } + }, + { + "size": 4, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg", + "props": { + "center": true, + "percent": 80 + } + } + }, + { + "size": 6, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg", + "props": { + "center": true, + "percent": 80 + } + } + } + ] + }, + "template_row2": { + "order": 2, + "height": 40, + "cols": [ + { + "size": 2, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg", + "props": { + "center": false, + "percent": 50, + "left": 10 + } + } + }, + { + "size": 4, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg", + "props": { + "center": false, + "percent": 50, + "top": 10 + } + } + }, + { + "size": 6, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg", + "props": { + "center": false, + "percent": 50, + "left": 15, + "top": 15 + } + } + } + ] + }, + "template_row3": { + "order": 3, + "height": 40, + "cols": [ + { + "size": 8, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg", + "props": { + "center": true, + "percent": 80 + } + } + }, + { + "size": 4, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg", + "props": { + "center": true, + "percent": 80 + } + } + } + ] + }, + "template_row4": { + "order": 4, + "height": 40, + "cols": [ + { + "size": 6, + "image": { + "order": 1, + "value": "docs/assets/images/frontpage.png", + "props": { + "center": false, + "percent": 80, + "top": 5, + "left": 10 + } + } + }, + { + "size": 4, + "image": { + "order": 1, + "value": "docs/assets/images/frontpage.png", + "props": { + "center": false, + "percent": 80, + "top": 5 + } + } + }, + { + "size": 2, + "image": { + "order": 1, + "value": "docs/assets/images/frontpage.png", + "props": { + "center": false, + "percent": 80, + "left": 5 + } + } + } + ] + }, + "template_row5": { + "order": 5, + "height": 40, + "cols": [ + { + "size": 6, + "image": { + "order": 1, + "value": "docs/assets/images/frontpage.png", + "props": { + "center": true, + "percent": 50 + } + } + }, + { + "size": 4, + "image": { + "order": 1, + "value": "docs/assets/images/frontpage.png", + "props": { + "center": true, + "percent": 50 + } + } + }, + { + "size": 2, + "image": { + "order": 1, + "value": "docs/assets/images/frontpage.png", + "props": { + "center": true, + "percent": 50 + } + } + } + ] + }, + "template_row6": { + "order": 6, + "height": 40, + "cols": [ + { + "size": 4, + "image": { + "order": 1, + "value": "docs/assets/images/frontpage.png", + "props": { + "center": true, + "percent": 80 + } + } + }, + { + "size": 8, + "image": { + "order": 1, + "value": "docs/assets/images/frontpage.png", + "props": { + "center": true, + "percent": 80 + } + } + } + ] + }, + "template_autorow1": { + "order": 7, + "cols": [ + { + "size": 4, + "image": { + "order": 1, + "value": "docs/assets/images/frontpage.png", + "props": { + "center": true, + "just_reference_width": true, + "percent": 20 + } + } + }, + { + "size": 8, + "image": { + "order": 1, + "value": "docs/assets/images/frontpage.png", + "props": { + "center": true, + "just_reference_width": true, + "percent": 30 + } + } + } + ] + }, + "template_autorow2": { + "order": 8, + "cols": [ + { + "size": 2, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg", + "props": { + "center": false, + "just_reference_width": true, + "percent": 50, + "left": 10 + } + } + }, + { + "size": 4, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg", + "props": { + "center": false, + "just_reference_width": true, + "percent": 50, + "top": 10 + } + } + }, + { + "size": 6, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg", + "props": { + "center": false, + "just_reference_width": true, + "percent": 50, + "left": 15, + "top": 15 + } + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/linegrid_template.json b/test/maroto/processor/json/linegrid_template.json new file mode 100644 index 00000000..97848335 --- /dev/null +++ b/test/maroto/processor/json/linegrid_template.json @@ -0,0 +1,230 @@ +{ + "builder": { + "debug": true + }, + "pages": { + "template_page": { + "order": 1, + "template_row1": { + "order": 1, + "height": 40, + "cols": [ + { + "size": 2, + "line": { + "order": 1 + } + }, + { + "size": 4, + "line": { + "order": 1 + } + }, + { + "size": 6, + "line": { + "order": 1 + } + } + ] + }, + "template_row2": { + "order": 2, + "height": 40, + "cols": [ + { + "size": 6, + "line": { + "order": 1 + } + }, + { + "size": 4, + "line": { + "order": 1 + } + }, + { + "size": 2, + "line": { + "order": 1 + } + } + ] + }, + "template_row3": { + "order": 3, + "height": 40, + "cols": [ + { + "size": 2, + "line": { + "order": 1, + "props": { + "thickness": 0.5 + } + } + }, + { + "size": 4, + "line": { + "order": 1, + "props": { + "color": { + "red": 255, + "green": 0, + "blue": 0 + } + } + } + }, + { + "size": 6, + "line": { + "order": 1, + "props": { + "orientation": "vertical" + } + } + } + ] + }, + "template_row4": { + "order": 4, + "height": 40, + "cols": [ + { + "size": 6, + "line": { + "order": 1, + "props": { + "offset_percent": 50 + } + } + }, + { + "size": 4, + "line": { + "order": 1, + "props": { + "offset_percent": 50, + "orientation": "vertical" + } + } + }, + { + "size": 2, + "line": { + "order": 1, + "props": { + "size_percent": 50 + } + } + } + ] + }, + "template_row5": { + "order": 5, + "height": 40, + "cols": [ + { + "size": 2, + "line": { + "order": 1, + "props": { + "style": "dashed" + } + } + }, + { + "size": 4, + "line": { + "order": 1, + "props": { + "color": { + "red": 255, + "green": 0, + "blue": 0 + }, + "style": "dashed", + "thickness": 0.8, + "orientation": "vertical", + "offset_percent": 70, + "size_percent": 70 + } + } + }, + { + "size": 6, + "line": { + "order": 1, + "props": { + "color": { + "red": 255, + "green": 0, + "blue": 0 + }, + "style": "dashed", + "thickness": 0.8, + "orientation": "horizontal", + "offset_percent": 40, + "size_percent": 40 + } + } + } + ] + }, + "template_autorow": { + "order": 6, + "cols": [ + { + "size": 2, + "line": { + "order": 1, + "props": { + "style": "dashed" + } + } + }, + { + "size": 4, + "line": { + "order": 1, + "props": { + "color": { + "red": 255, + "green": 0, + "blue": 0 + }, + "style": "dashed", + "thickness": 0.8, + "orientation": "vertical", + "offset_percent": 70, + "size_percent": 70 + } + } + }, + { + "size": 6, + "line": { + "order": 1, + "props": { + "color": { + "red": 255, + "green": 0, + "blue": 0 + }, + "style": "dashed", + "thickness": 0.8, + "orientation": "horizontal", + "offset_percent": 40, + "size_percent": 40 + } + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/lowmemory_content.json b/test/maroto/processor/json/lowmemory_content.json new file mode 100644 index 00000000..a25ab2b3 --- /dev/null +++ b/test/maroto/processor/json/lowmemory_content.json @@ -0,0 +1,258 @@ +{ + "pages": { + "template_page": { + "list_rows": [ + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + } + ] + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/lowmemory_template.json b/test/maroto/processor/json/lowmemory_template.json new file mode 100644 index 00000000..2faf7833 --- /dev/null +++ b/test/maroto/processor/json/lowmemory_template.json @@ -0,0 +1,30 @@ +{ + "builder": { + "debug": true, + "sequential_low_memory_mode": 7, + "page_number": {} + }, + "pages": { + "template_page": { + "order": 1, + "list_rows": { + "order": 1, + "template_row": { + "order": 1, + "height": 10, + "cols": [ + { + "text": { + "order": 1, + "source_key": "text_value", + "props": { + "size": 8 + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/margins_content.json b/test/maroto/processor/json/margins_content.json new file mode 100644 index 00000000..9f25fdd9 --- /dev/null +++ b/test/maroto/processor/json/margins_content.json @@ -0,0 +1,58 @@ +{ + "pages": { + "template_page": { + "list_rows": [ + { + "template_row": { + "text_value": "any text" + } + }, + { + "template_row": { + "text_value": "any text" + } + }, + { + "template_row": { + "text_value": "any text" + } + }, + { + "template_row": { + "text_value": "any text" + } + }, + { + "template_row": { + "text_value": "any text" + } + }, + { + "template_row": { + "text_value": "any text" + } + }, + { + "template_row": { + "text_value": "any text" + } + }, + { + "template_row": { + "text_value": "any text" + } + }, + { + "template_row": { + "text_value": "any text" + } + }, + { + "template_row": { + "text_value": "any text" + } + } + ] + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/margins_template.json b/test/maroto/processor/json/margins_template.json new file mode 100644 index 00000000..2366c2dd --- /dev/null +++ b/test/maroto/processor/json/margins_template.json @@ -0,0 +1,63 @@ +{ + "builder": { + "debug": true, + "margins": { + "top": 20, + "left": 20, + "right": 20 + } + }, + "header": { + "template_row": { + "order": 1, + "height": 40, + "cols": [ + { + "size": 4, + "image": { + "order": 1, + "value": "docs/assets/images/gopherbw.png", + "props": { + "center": true, + "percent": 50 + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "Margins Test", + "props": { + "size": 12, + "top": 12 + } + } + }, + { + "size": 4 + } + ] + } + }, + "pages": { + "template_page": { + "order": 1, + "list_rows": { + "order": 1, + "template_row": { + "order": 1, + "height": 30, + "cols": [ + { + "text": { + "order": 1, + "source_key": "text_value" + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/maxgridsum_template.json b/test/maroto/processor/json/maxgridsum_template.json new file mode 100644 index 00000000..1aa3d60b --- /dev/null +++ b/test/maroto/processor/json/maxgridsum_template.json @@ -0,0 +1,374 @@ +{ + "builder": { + "debug": true, + "max_grid_size": 14 + }, + "pages": { + "template_page": { + "order": 1, + "template_title_row": { + "height": 10, + "order": 1, + "cols": [ + { + "text": { + "order": 1, + "value":"Table with 14 Columns", + "props": { + "style": "bold" + } + } + } + ] + }, + "template_header_row": { + "order": 2, + "height": 8, + "cols": [ + { + "size": 1, + "text": { + "order": 1, + "value": "H 0", + "props": { + "style": "bold", + "top": 1.5, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "H 1", + "props": { + "style": "bold", + "top": 1.5, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "H 2", + "props": { + "style": "bold", + "top": 1.5, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "H 3", + "props": { + "style": "bold", + "top": 1.5, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "H 4", + "props": { + "style": "bold", + "top": 1.5, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "H 5", + "props": { + "style": "bold", + "top": 1.5, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "H 6", + "props": { + "style": "bold", + "top": 1.5, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "H 7", + "props": { + "style": "bold", + "top": 1.5, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "H 8", + "props": { + "style": "bold", + "top": 1.5, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "H 9", + "props": { + "style": "bold", + "top": 1.5, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "H 10", + "props": { + "style": "bold", + "top": 1.5, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "H 11", + "props": { + "style": "bold", + "top": 1.5, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "H 12", + "props": { + "style": "bold", + "top": 1.5, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "H 13", + "props": { + "style": "bold", + "top": 1.5, + "left": 1.5 + } + } + } + ] + }, + "template_content_row": { + "order": 3, + "height": 8, + "cols": [ + { + "size": 1, + "text": { + "order": 1, + "value": "C 0", + "props": { + "top": 1, + "size": 9, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "C 1", + "props": { + "top": 1, + "size": 9, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "C 2", + "props": { + "top": 1, + "size": 9, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "C 3", + "props": { + "top": 1, + "size": 9, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "C 4", + "props": { + "top": 1, + "size": 9, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "C 5", + "props": { + "top": 1, + "size": 9, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "C 6", + "props": { + "top": 1, + "size": 9, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "C 7", + "props": { + "top": 1, + "size": 9, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "C 8", + "props": { + "top": 1, + "size": 9, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "C 9", + "props": { + "top": 1, + "size": 9, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "C 10", + "props": { + "top": 1, + "size": 9, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "C 11", + "props": { + "top": 1, + "size": 9, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "C 12", + "props": { + "top": 1, + "size": 9, + "left": 1.5 + } + } + }, + { + "size": 1, + "text": { + "order": 1, + "value": "C 13", + "props": { + "top": 1, + "size": 9, + "left": 1.5 + } + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/metadata_template.json b/test/maroto/processor/json/metadata_template.json new file mode 100644 index 00000000..65864f94 --- /dev/null +++ b/test/maroto/processor/json/metadata_template.json @@ -0,0 +1,45 @@ +{ + "builder": { + "metadata": { + "author": { + "text": "author", + "utf8": false + }, + "creator": { + "text": "creator", + "utf8": false + }, + "subject": { + "text": "subject", + "utf8": false + }, + "title": { + "text": "title", + "utf8": false + }, + "keywords": { + "text": "keyword", + "utf8": false + }, + "creationDate": "2025-02-01 10:50:05" + } + }, + "pages": { + "template_page": { + "order": 1, + "template_row": { + "height": 30, + "order": 1, + "cols": [ + { + "text": { + "order": 1, + "value": "metadatas" + } + } + ] + + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/orientation_template.json b/test/maroto/processor/json/orientation_template.json new file mode 100644 index 00000000..e4b1ce6f --- /dev/null +++ b/test/maroto/processor/json/orientation_template.json @@ -0,0 +1,23 @@ +{ + "builder": { + "orientation": "horizontal", + "debug": true + }, + "pages": { + "template_page": { + "order": 1, + "template_row": { + "order": 1, + "height": 30, + "cols": [ + { + "text": { + "order": 1, + "value": "content" + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/pagenumber_content.json b/test/maroto/processor/json/pagenumber_content.json new file mode 100644 index 00000000..1fb5ab0e --- /dev/null +++ b/test/maroto/processor/json/pagenumber_content.json @@ -0,0 +1,83 @@ +{ + "pages": { + "template_page": { + "list_rows": [ + { + "template_row": { + "text_value": "dummy text" + } + }, + { + "template_row": { + "text_value": "dummy text" + } + }, + { + "template_row": { + "text_value": "dummy text" + } + }, + { + "template_row": { + "text_value": "dummy text" + } + }, + { + "template_row": { + "text_value": "dummy text" + } + }, + { + "template_row": { + "text_value": "dummy text" + } + }, + { + "template_row": { + "text_value": "dummy text" + } + }, + { + "template_row": { + "text_value": "dummy text" + } + }, + { + "template_row": { + "text_value": "dummy text" + } + }, + { + "template_row": { + "text_value": "dummy text" + } + }, + { + "template_row": { + "text_value": "dummy text" + } + }, + { + "template_row": { + "text_value": "dummy text" + } + }, + { + "template_row": { + "text_value": "dummy text" + } + }, + { + "template_row": { + "text_value": "dummy text" + } + }, + { + "template_row": { + "text_value": "dummy text" + } + } + ] + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/pagenumber_template.json b/test/maroto/processor/json/pagenumber_template.json new file mode 100644 index 00000000..81145719 --- /dev/null +++ b/test/maroto/processor/json/pagenumber_template.json @@ -0,0 +1,35 @@ +{ + "builder": { + "debug": true, + "page_number": { + "pattern": "Page {current} of {total}", + "place": "bottom", + "family": "courier", + "style": "bold", + "size": 9, + "color": { + "red": 255 + } + } + }, + "pages": { + "template_page": { + "order": 1, + "list_rows": { + "order": 1, + "template_row": { + "order": 1, + "height": 20, + "cols": [ + { + "text": { + "order": 1, + "source_key": "text_value" + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/parallelism_content.json b/test/maroto/processor/json/parallelism_content.json new file mode 100644 index 00000000..a25ab2b3 --- /dev/null +++ b/test/maroto/processor/json/parallelism_content.json @@ -0,0 +1,258 @@ +{ + "pages": { + "template_page": { + "list_rows": [ + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + }, + { + "template_row": { + "text_value": "Dummy text" + } + } + ] + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/parallelism_template.json b/test/maroto/processor/json/parallelism_template.json new file mode 100644 index 00000000..643c1dae --- /dev/null +++ b/test/maroto/processor/json/parallelism_template.json @@ -0,0 +1,31 @@ +{ + "builder": { + "debug": true, + "concurrent_mode": 7, + "page_number": {} + }, + + "pages": { + "template_page": { + "order": 1, + "list_rows": { + "order": 1, + "template_row": { + "order": 1, + "height": 10, + "cols": [ + { + "text": { + "order": 1, + "source_key": "text_value", + "props": { + "size": 8 + } + } + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/protection_template.json b/test/maroto/processor/json/protection_template.json new file mode 100644 index 00000000..97894cf3 --- /dev/null +++ b/test/maroto/processor/json/protection_template.json @@ -0,0 +1,26 @@ +{ + "builder": { + "protection": { + "type": "none", + "user_password": "user", + "owner_password": "owner" + } + }, + "pages": { + "template_page": { + "order": 1, + "template_row": { + "order": 1, + "height": 30, + "cols": [ + { + "text": { + "order": 1, + "value": "supersecret content" + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/qrcodegrid_template.json b/test/maroto/processor/json/qrcodegrid_template.json new file mode 100644 index 00000000..dd7e117f --- /dev/null +++ b/test/maroto/processor/json/qrcodegrid_template.json @@ -0,0 +1,201 @@ +{ + "builder": { + "debug": true + }, + "pages": { + "template_page": { + "order": 1, + "qr_code_row1": { + "order": 1, + "height": 40, + "cols": [ + { + "size": 2, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 50 + } + } + }, + { + "size": 4, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 75 + } + } + }, + { + "size": 6, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 100 + } + } + } + ] + }, + "qr_code_center_row1": { + "order": 2, + "height": 40, + "cols": [ + { + "size": 2, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "center": true, + "percent": 50 + } + } + }, + { + "size": 4, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "center": true, + "percent": 75 + } + } + }, + { + "size": 6, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "center": true, + "percent": 100 + } + } + } + ] + }, + "qr_code_row2": { + "order": 3, + "height": 40, + "cols": [ + { + "size": 6, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 50 + } + } + }, + { + "size": 4, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 75 + } + } + }, + { + "size": 2, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "percent": 100 + } + } + } + ] + }, + "qr_code_center_row2": { + "order": 4, + "height": 40, + "cols": [ + { + "size": 6, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "center": true, + "percent": 50 + } + } + }, + { + "size": 4, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "center": true, + "percent": 75 + } + } + }, + { + "size": 2, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "center": true, + "percent": 100 + } + } + } + ] + }, + "qr_code_auto_row": { + "order": 5, + "cols": [ + { + "size": 6, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "center": true, + "percent": 30, + "just_reference_width": true + } + } + }, + { + "size": 4, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "center": true, + "percent": 75, + "just_reference_width": true + } + } + }, + { + "size": 2, + "qr_code": { + "order": 1, + "value": "https://github.com/johnfercher/maroto", + "props": { + "center": true, + "percent": 100, + "just_reference_width": true + } + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/signature_template.json b/test/maroto/processor/json/signature_template.json new file mode 100644 index 00000000..d671335f --- /dev/null +++ b/test/maroto/processor/json/signature_template.json @@ -0,0 +1,162 @@ +{ + "builder": { + "debug": true + }, + "pages": { + "template_page": { + "order": 1, + "template_row1": { + "order": 1, + "height": 40, + "cols": [ + { + "size": 2, + "signature": { + "order": 1, + "value": "Signature 1" + } + }, + { + "size": 4, + "signature": { + "order": 1, + "value": "Signature 2", + "props": { + "font_family": "courier" + } + } + }, + { + "size": 6, + "signature": { + "order": 1, + "value": "Signature 3", + "props": { + "font_style": "bold_italic" + } + } + } + ] + }, + "template_row2": { + "order": 2, + "height": 40, + "cols": [ + { + "size": 6, + "signature": { + "order": 1, + "value": "Signature 4", + "props": { + "font_style": "italic" + } + } + }, + { + "size": 4, + "signature": { + "order": 1, + "value": "Signature 5", + "props": { + "font_size": 12 + } + } + }, + { + "size": 2, + "signature": { + "order": 1, + "value": "Signature 6", + "props": { + "font_color": { + "red": 255, + "blue": 0, + "green": 0 + } + } + } + } + ] + }, + "template_row3": { + "order": 3, + "height": 40, + "cols": [ + { + "size": 4, + "signature": { + "order": 1, + "value": "Signature 7", + "props": { + "line_color": { + "red": 255, + "blue": 0, + "green": 0 + } + } + } + }, + { + "size": 4, + "signature": { + "order": 1, + "value": "Signature 8", + "props": { + "line_style": "dashed" + } + } + }, + { + "size": 4, + "signature": { + "order": 1, + "value": "Signature 9", + "props": { + "line_thickness": 0.5 + } + } + } + ] + }, + "template_autorow": { + "order": 4, + "cols": [ + { + "size": 4, + "signature": { + "order": 1, + "value": "Signature 7", + "props": { + "line_color": { + "red": 255, + "blue": 0, + "green": 0 + } + } + } + }, + { + "size": 4, + "signature": { + "order": 1, + "value": "Signature 8", + "props": { + "line_style": "dashed" + } + } + }, + { + "size": 4, + "signature": { + "order": 1, + "value": "Signature 9", + "props": { + "line_thickness": 0.5 + } + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/simple_pdf_content.json b/test/maroto/processor/json/simple_pdf_content.json new file mode 100644 index 00000000..6e6aa28a --- /dev/null +++ b/test/maroto/processor/json/simple_pdf_content.json @@ -0,0 +1,38 @@ +{ + "header": { + "row_header": { + "header_value": "header text" + } + }, + "footer": { + "row_footer": { + "footer_value": "footer text" + } + }, + "pages": { + "page_template_1": { + "row_1": { + "value_1": "row 1", + "value_2": "row 1" + }, + "list_row_1": [ + { + "row": { + "value_2": "row 2" + }, + "row_1": { + "value_2": "row 3" + } + }, + { + "row": { + "value_2": "row 4" + }, + "row_1": { + "value_2": "row 5" + } + } + ] + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/simple_pdf_templates.json b/test/maroto/processor/json/simple_pdf_templates.json new file mode 100644 index 00000000..bda2b326 --- /dev/null +++ b/test/maroto/processor/json/simple_pdf_templates.json @@ -0,0 +1,81 @@ +{ + "header": { + "row_header": { + "order": 1, + "cols": [ + { + "text": { + "order": 1, + "source_key": "header_value" + }, + "size": 12 + } + ] + } + }, + "footer": { + "row_footer": { + "order": 1, + "cols": [ + { + "text": { + "order": 1, + "source_key": "footer_value" + }, + "size": 12 + } + ] + } + }, + "pages": { + "page_template_1": { + "order": 1, + "row_1": { + "order": 1, + "cols": [ + { + "text": { + "order": 1, + "source_key": "value_1" + }, + "size": 6.0 + }, + { + "text": { + "order": 1, + "source_key": "value_2" + }, + "size": 6.0 + } + ] + }, + "list_row_1": { + "order": 2, + "row": { + "order": 1, + "cols": [ + { + "text": { + "order": 1, + "source_key": "value_2" + }, + "size": 10.0 + } + ] + }, + "row_1": { + "order": 2, + "cols": [ + { + "text": { + "order": 1, + "source_key": "value_2" + }, + "size": 10.0 + } + ] + } + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/simplest_template.json b/test/maroto/processor/json/simplest_template.json new file mode 100644 index 00000000..4377f7c5 --- /dev/null +++ b/test/maroto/processor/json/simplest_template.json @@ -0,0 +1,91 @@ +{ + "pages": { + "template_page": { + "order": 1, + "template_row1": { + "order": 1, + "height": 20, + "cols": [ + { + "size": 4, + "bar_code": { + "order": 1, + "value": "barcode" + } + }, + { + "size": 4, + "matrix_code": { + "order": 1, + "value": "matrixcode" + } + }, + { + "size": 4, + "qr_code": { + "order": 1, + "value": "qrcode" + } + } + ] + }, + "tepmlate_row2": { + "order": 2, + "height": 10, + "cols": [ + { + "size": 12 + } + ] + }, + "template_row3": { + "order": 3, + "height": 20, + "cols": [ + { + "size": 4, + "image": { + "order": 1, + "value": "docs/assets/images/biplane.jpg" + } + }, + { + "size": 4, + "signature": { + "order": 1, + "value": "signature" + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "text" + } + } + ] + }, + "template_row4": { + "order": 4, + "height": 10, + "cols": [ + { + "size": 12 + } + ] + }, + "template_row5": { + "order": 5, + "height": 20, + "cols": [ + { + "size": 12, + "line": { + "order": 1 + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/json/textgrid_template.json b/test/maroto/processor/json/textgrid_template.json new file mode 100644 index 00000000..8fdf8304 --- /dev/null +++ b/test/maroto/processor/json/textgrid_template.json @@ -0,0 +1,424 @@ +{ + "builder": { + "debug": true + }, + "pages": { + "template_page": { + "order": 1, + "template_row1": { + "order": 1, + "height": 40, + "cols": [ + { + "size": 2, + "text": { + "order": 1, + "value": "Red text", + "props": { + "color": { + "red": 255, + "green": 0, + "blue": 0 + } + } + } + }, + { + "size": 6, + "text": { + "order": 1, + "value": "Green text", + "props": { + "color": { + "red": 0, + "green": 255, + "blue": 0 + } + } + } + }, + { + "size": 4, + "text":{ + "order": 1, + "value": "Blue text", + "props": { + "color": { + "red": 0, + "green": 0, + "blue": 255 + } + } + } + } + ] + }, + "template_row2": { + "order": 2, + "height": 40, + "cols": [ + { + "size": 2, + "text": { + "order": 1, + "value": "Left-aligned text" + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "Centered text", + "props": { + "align": "center" + } + } + + }, + { + "size": 6, + "text": { + "order": 1, + "value": "Right-aligned text", + "props": { + "align": "right" + } + } + } + ] + }, + "template_row3": { + "order": 3, + "height": 10, + "cols": [ + { + "text": { + "order": 1, + "value": "Aligned unindented text" + } + } + ] + }, + "template_row4": { + "order": 4, + "height": 40, + "cols": [ + { + "size": 2, + "text": { + "order": 1, + "value": "Left-aligned text", + "props": { + "top": 3, + "left": 3, + "align": "left" + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "Centered text", + "props": { + "top": 3, + "align": "center" + } + } + }, + { + "size": 6, + "text":{ + "order": 1, + "value": "Right-aligned text", + "props": { + "top": 3, + "right": 3, + "align": "right" + } + } + } + ] + }, + "template_row5": { + "order": 5, + "height": 10, + "cols": [ + { + "text": { + "order": 1, + "value": "Aligned text with indentation" + } + } + ] + }, + "template_row6": { + "order": 6, + "height": 40, + "cols": [ + { + "size": 2, + "text": { + "order": 1, + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "props": { + "align": "left" + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "props": { + "align": "center" + } + } + }, + { + "size": 6, + "text": { + "order": 1, + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "props": { + "align": "right" + } + } + } + ] + }, + "template_row7": { + "order": 7, + "height": 10, + "cols": [ + { + "text": { + "order": 1, + "value": "Multiline text" + } + } + ] + }, + "template_row8": { + "order": 8, + "height": 40, + "cols": [ + { + "size": 2, + "text": { + "order": 1, + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "props": { + "top": 3, + "left": 3, + "right": 3, + "align": "left", + "break_line_strategy": "dash_strategy" + } + } + + }, + { + "size": 4, + "text": { + "order": 1, + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "props": { + "top": 3, + "left": 3, + "right": 3, + "align": "center" + } + } + }, + { + "size": 6, + "text": { + "order": 1, + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "props": { + "top": 3, + "left": 3, + "right": 3, + "align": "right" + } + } + } + ] + }, + "template_row9": { + "order": 9, + "height": 10, + "cols": [ + { + "text": { + "order": 1, + "value": "Multiline text with indentation" + } + } + ] + }, + "template_row10": { + "order": 10, + "height": 10, + "cols": [ + { + "text": { + "order": 1, + "value": "text with hyperlink", + "props": { + "hyperlink": "https://google.com" + } + } + } + ] + }, + "template_row11": { + "order": 11, + "height": 45, + "cols": [ + { + "size": 2, + "text": { + "order": 1, + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "props": { + "top": 3, + "left": 3, + "right": 3, + "align": "justify", + "break_line_strategy": "dash_strategy" + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise. This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "props": { + "top": 10, + "left": 3, + "right": 3, + "align": "justify" + } + } + }, + { + "size": 6, + "text": { + "order": 1, + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise. This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "props": { + "top": 10, + "left": 10, + "right": 10, + "align": "justify", + "hyperlink": "https://google.com" + } + } + } + ] + }, + "template_row12": { + "order": 12, + "height": 10, + "cols": [ + { + "text": { + "order": 1, + "value": "Justify-aligned text", + "props": { + "align": "justify" + } + } + } + ] + }, + "template_row13": { + "order": 13, + "cols": [ + { + "size": 2, + "text": { + "order": 1, + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "props": { + "top": 0, + "left": 3, + "right": 3, + "align": "justify", + "break_line_strategy": "dash_strategy" + } + } + }, + { + "size": 4, + "text": { + "order": 1, + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise. This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "props": { + "top": 0, + "left": 3, + "right": 3, + "align": "justify" + } + } + }, + { + "size": 6, + "text": { + "order": 1, + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise. This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise. This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "props": { + "top": 0, + "left": 10, + "right": 10, + "align": "justify", + "hyperlink": "https://google.com" + } + } + } + ] + }, + "template_row14": { + "order": 14, + "cols": [ + { + "size": 12, + "text": { + "order": 1, + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise. This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise. This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "props": { + "left": 3, + "right": 3, + "align": "justify", + "break_line_strategy": "empty_space_strategyt" + } + } + } + ] + }, + "template_row15": { + "order": 15, + "cols": [ + { + "size": 12, + "text": { + "order": 1, + "value": "This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise. This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise. This is a longer sentence that will be broken into multiple lines as it does not fit into the column otherwise.", + "props": { + "left": 3, + "right": 3, + "align": "justify", + "break_line_strategy": "empty_space_strategy", + "vertical_padding": 10 + } + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/maroto/processor/provider/barcode.json b/test/maroto/processor/provider/barcode.json new file mode 100644 index 00000000..5df7311b --- /dev/null +++ b/test/maroto/processor/provider/barcode.json @@ -0,0 +1,11 @@ +{ + "value": "code", + "type": "barcode", + "details": { + "prop_left": 10, + "prop_percent": 100, + "prop_proportion_height": 2, + "prop_proportion_width": 10, + "prop_top": 10 + } +} \ No newline at end of file diff --git a/test/maroto/processor/provider/document_with_footer.json b/test/maroto/processor/provider/document_with_footer.json new file mode 100644 index 00000000..e219b167 --- /dev/null +++ b/test/maroto/processor/provider/document_with_footer.json @@ -0,0 +1,61 @@ +{ + "type": "maroto", + "details": { + "chunk_workers": 1, + "config_margin_bottom": 20.0025, + "config_margin_left": 10, + "config_margin_right": 10, + "config_margin_top": 10, + "config_max_grid_sum": 12, + "config_provider_type": "gofpdf", + "generation_mode": "sequential", + "maroto_dimension_height": 297, + "maroto_dimension_width": 210, + "prop_font_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10 + }, + "nodes": [ + { + "type": "page", + "nodes": [ + { + "value": 263.46972222222223, + "type": "row", + "nodes": [ + { + "value": 12, + "type": "col" + } + ] + }, + { + "value": 3.527777777777778, + "type": "row", + "nodes": [ + { + "value": 0, + "type": "col", + "details": { + "is_max": true + }, + "nodes": [ + { + "value": "footer", + "type": "text", + "details": { + "prop_align": "L", + "prop_breakline_strategy": "empty_space_strategy", + "prop_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10 + } + } + ] + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/test/maroto/processor/provider/document_with_header.json b/test/maroto/processor/provider/document_with_header.json new file mode 100644 index 00000000..1b40d055 --- /dev/null +++ b/test/maroto/processor/provider/document_with_header.json @@ -0,0 +1,61 @@ +{ + "type": "maroto", + "details": { + "chunk_workers": 1, + "config_margin_bottom": 20.0025, + "config_margin_left": 10, + "config_margin_right": 10, + "config_margin_top": 10, + "config_max_grid_sum": 12, + "config_provider_type": "gofpdf", + "generation_mode": "sequential", + "maroto_dimension_height": 297, + "maroto_dimension_width": 210, + "prop_font_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10 + }, + "nodes": [ + { + "type": "page", + "nodes": [ + { + "value": 3.527777777777778, + "type": "row", + "nodes": [ + { + "value": 0, + "type": "col", + "details": { + "is_max": true + }, + "nodes": [ + { + "value": "header", + "type": "text", + "details": { + "prop_align": "L", + "prop_breakline_strategy": "empty_space_strategy", + "prop_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10 + } + } + ] + } + ] + }, + { + "value": 263.46972222222223, + "type": "row", + "nodes": [ + { + "value": 12, + "type": "col" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/test/maroto/processor/provider/document_with_page.json b/test/maroto/processor/provider/document_with_page.json new file mode 100644 index 00000000..888a878a --- /dev/null +++ b/test/maroto/processor/provider/document_with_page.json @@ -0,0 +1,48 @@ +{ + "type": "maroto", + "details": { + "chunk_workers": 1, + "config_margin_bottom": 20.0025, + "config_margin_left": 10, + "config_margin_right": 10, + "config_margin_top": 10, + "config_max_grid_sum": 12, + "config_provider_type": "gofpdf", + "generation_mode": "sequential", + "maroto_dimension_height": 297, + "maroto_dimension_width": 210, + "prop_font_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10 + }, + "nodes": [ + { + "type": "page", + "nodes": [ + { + "value": 10, + "type": "row", + "nodes": [ + { + "value": 0, + "type": "col", + "details": { + "is_max": true + } + } + ] + }, + { + "value": 256.9975, + "type": "row", + "nodes": [ + { + "value": 12, + "type": "col" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/test/maroto/processor/provider/image.json b/test/maroto/processor/provider/image.json new file mode 100644 index 00000000..15d53a0e --- /dev/null +++ b/test/maroto/processor/provider/image.json @@ -0,0 +1,9 @@ +{ + "value": "img.png", + "type": "fileImage", + "details": { + "prop_left": 10, + "prop_percent": 100, + "prop_top": 10 + } +} \ No newline at end of file diff --git a/test/maroto/processor/provider/line.json b/test/maroto/processor/provider/line.json new file mode 100644 index 00000000..10301100 --- /dev/null +++ b/test/maroto/processor/provider/line.json @@ -0,0 +1,11 @@ +{ + "type": "line", + "details": { + "prop_color": "RGB(10, 10, 10)", + "prop_offset_percent": 50, + "prop_orientation": "vertical", + "prop_size_percent": 50, + "prop_style": "solid", + "prop_thickness": 10 + } +} \ No newline at end of file diff --git a/test/maroto/processor/provider/matrixcode.json b/test/maroto/processor/provider/matrixcode.json new file mode 100644 index 00000000..bb63e3c8 --- /dev/null +++ b/test/maroto/processor/provider/matrixcode.json @@ -0,0 +1,9 @@ +{ + "value": "code", + "type": "matrixcode", + "details": { + "prop_left": 10, + "prop_percent": 100, + "prop_top": 10 + } +} \ No newline at end of file diff --git a/test/maroto/processor/provider/qrcode.json b/test/maroto/processor/provider/qrcode.json new file mode 100644 index 00000000..e293eb31 --- /dev/null +++ b/test/maroto/processor/provider/qrcode.json @@ -0,0 +1,9 @@ +{ + "value": "code", + "type": "qrcode", + "details": { + "prop_left": 10, + "prop_percent": 100, + "prop_top": 10 + } +} \ No newline at end of file diff --git a/test/maroto/processor/provider/signature.json b/test/maroto/processor/provider/signature.json new file mode 100644 index 00000000..db4667fa --- /dev/null +++ b/test/maroto/processor/provider/signature.json @@ -0,0 +1,13 @@ +{ + "value": "signature", + "type": "signature", + "details": { + "prop_font_color": "RGB(10, 10, 10)", + "prop_font_family": "Arial", + "prop_font_size": 10, + "prop_font_style": "bold", + "prop_line_color": "RGB(10, 10, 10)", + "prop_line_style": "solid", + "prop_line_thickness": 10 + } +} \ No newline at end of file diff --git a/test/maroto/processor/provider/text.json b/test/maroto/processor/provider/text.json new file mode 100644 index 00000000..876ddbbf --- /dev/null +++ b/test/maroto/processor/provider/text.json @@ -0,0 +1,17 @@ +{ + "value": "text", + "type": "text", + "details": { + "prop_align": "center", + "prop_breakline_strategy": "dash_strategy", + "prop_color": "RGB(10, 10, 10)", + "prop_font_family": "Arial", + "prop_font_size": 10, + "prop_font_style": "bold", + "prop_hyperlink": "test", + "prop_left": 10, + "prop_right": 10, + "prop_top": 10, + "prop_vertical_padding": 10 + } +} \ No newline at end of file diff --git a/test/maroto/processor/simple_pdf.json b/test/maroto/processor/simple_pdf.json new file mode 100644 index 00000000..74da69af --- /dev/null +++ b/test/maroto/processor/simple_pdf.json @@ -0,0 +1,213 @@ +{ + "type": "maroto", + "details": { + "chunk_workers": 1, + "config_margin_bottom": 20.0025, + "config_margin_left": 10, + "config_margin_right": 10, + "config_margin_top": 10, + "config_max_grid_sum": 12, + "config_provider_type": "gofpdf", + "generation_mode": "sequential", + "maroto_dimension_height": 297, + "maroto_dimension_width": 210, + "prop_font_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10 + }, + "nodes": [ + { + "type": "page", + "nodes": [ + { + "value": 3.527777777777778, + "type": "row", + "nodes": [ + { + "value": 12, + "type": "col", + "nodes": [ + { + "value": "header text", + "type": "text", + "details": { + "prop_align": "L", + "prop_breakline_strategy": "empty_space_strategy", + "prop_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10 + } + } + ] + } + ] + }, + { + "value": 3.527777777777778, + "type": "row", + "nodes": [ + { + "value": 6, + "type": "col", + "nodes": [ + { + "value": "row 1", + "type": "text", + "details": { + "prop_align": "L", + "prop_breakline_strategy": "empty_space_strategy", + "prop_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10 + } + } + ] + }, + { + "value": 6, + "type": "col", + "nodes": [ + { + "value": "row 1", + "type": "text", + "details": { + "prop_align": "L", + "prop_breakline_strategy": "empty_space_strategy", + "prop_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10 + } + } + ] + } + ] + }, + { + "value": 3.527777777777778, + "type": "row", + "nodes": [ + { + "value": 10, + "type": "col", + "nodes": [ + { + "value": "row 2", + "type": "text", + "details": { + "prop_align": "L", + "prop_breakline_strategy": "empty_space_strategy", + "prop_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10 + } + } + ] + } + ] + }, + { + "value": 3.527777777777778, + "type": "row", + "nodes": [ + { + "value": 10, + "type": "col", + "nodes": [ + { + "value": "row 3", + "type": "text", + "details": { + "prop_align": "L", + "prop_breakline_strategy": "empty_space_strategy", + "prop_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10 + } + } + ] + } + ] + }, + { + "value": 3.527777777777778, + "type": "row", + "nodes": [ + { + "value": 10, + "type": "col", + "nodes": [ + { + "value": "row 4", + "type": "text", + "details": { + "prop_align": "L", + "prop_breakline_strategy": "empty_space_strategy", + "prop_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10 + } + } + ] + } + ] + }, + { + "value": 3.527777777777778, + "type": "row", + "nodes": [ + { + "value": 10, + "type": "col", + "nodes": [ + { + "value": "row 5", + "type": "text", + "details": { + "prop_align": "L", + "prop_breakline_strategy": "empty_space_strategy", + "prop_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10 + } + } + ] + } + ] + }, + { + "value": 242.30305555555557, + "type": "row", + "nodes": [ + { + "value": 12, + "type": "col" + } + ] + }, + { + "value": 3.527777777777778, + "type": "row", + "nodes": [ + { + "value": 12, + "type": "col", + "nodes": [ + { + "value": "footer text", + "type": "text", + "details": { + "prop_align": "L", + "prop_breakline_strategy": "empty_space_strategy", + "prop_color": "RGB(0, 0, 0)", + "prop_font_family": "arial", + "prop_font_size": 10 + } + } + ] + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/test/maroto/processor/without_all_builder_props.json b/test/maroto/processor/without_all_builder_props.json new file mode 100644 index 00000000..ca025525 --- /dev/null +++ b/test/maroto/processor/without_all_builder_props.json @@ -0,0 +1,5 @@ +{ + "dimensions": { + + } +} \ No newline at end of file diff --git a/test/maroto/processor/without_builder_props.json b/test/maroto/processor/without_builder_props.json new file mode 100644 index 00000000..c1860fa3 --- /dev/null +++ b/test/maroto/processor/without_builder_props.json @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file