feat: tests
This commit is contained in:
16
AGENTS.md
16
AGENTS.md
@@ -25,6 +25,22 @@ Alternatively, you can use Docker for a containerized environment:
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
## Writing Tests
|
||||
|
||||
All tests are written using the go standard library and are table driven.
|
||||
In this application no libraries like testify are used. Mocks are written in
|
||||
the test file using this schema:
|
||||
|
||||
```go
|
||||
type Mock struct {
|
||||
Foo func (string) string
|
||||
}
|
||||
|
||||
func (m Mock) Foo(in string) string {
|
||||
return m.Foo(in)
|
||||
}
|
||||
```
|
||||
|
||||
## Running Tests
|
||||
|
||||
To run all tests for the project, use the following command:
|
||||
|
||||
6
go.mod
6
go.mod
@@ -6,22 +6,26 @@ require (
|
||||
code.gitea.io/sdk/gitea v0.21.0
|
||||
github.com/caarlos0/env/v10 v10.0.0
|
||||
github.com/gomarkdown/markdown v0.0.0-20250810172220-2e2c11897d1a
|
||||
github.com/itzg/go-flagsfiller v1.16.0
|
||||
github.com/jedib0t/go-pretty/v6 v6.6.8
|
||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
|
||||
github.com/starwalkn/gotenberg-go-client/v8 v8.11.0
|
||||
github.com/itzg/go-flagsfiller v1.16.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/42wim/httpsig v1.2.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/davidmz/go-pageant v1.0.2 // indirect
|
||||
github.com/go-fed/httpsig v1.1.0 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/iancoleman/strcase v0.3.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
golang.org/x/crypto v0.41.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
6
go.sum
6
go.sum
@@ -31,8 +31,12 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
|
||||
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/starwalkn/gotenberg-go-client/v8 v8.11.0 h1:9hKCcoWegZ0yrZ0tEl5gKlMyH2YraYO0R7zDyL0ZL/U=
|
||||
github.com/starwalkn/gotenberg-go-client/v8 v8.11.0/go.mod h1:5q9nAJ3/lub4hSCT6QYl8cOjnfQ/B+spEzC4TAPVXd8=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
@@ -55,5 +59,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
162
pkg/invoice/invoice_test.go
Normal file
162
pkg/invoice/invoice_test.go
Normal file
@@ -0,0 +1,162 @@
|
||||
package invoice
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"git.schreifuchs.ch/lou-taylor/accounting/pkg/invoice/model"
|
||||
)
|
||||
|
||||
// MockGiteaClient is a mock implementation of the GiteaClient interface.
|
||||
type MockGiteaClient struct {
|
||||
ListRepoIssuesFunc func(owner, repo string, opt gitea.ListIssueOption) ([]*gitea.Issue, *gitea.Response, error)
|
||||
}
|
||||
|
||||
func (m *MockGiteaClient) ListRepoIssues(owner, repo string, opt gitea.ListIssueOption) ([]*gitea.Issue, *gitea.Response, error) {
|
||||
if m.ListRepoIssuesFunc != nil {
|
||||
return m.ListRepoIssuesFunc(owner, repo, opt)
|
||||
}
|
||||
return nil, nil, errors.New("ListRepoIssuesFunc not implemented")
|
||||
}
|
||||
|
||||
// MockPdfGenerator is a mock implementation of the PdfGenerator interface.
|
||||
type MockPdfGenerator struct {
|
||||
HtmlToPdfFunc func(html string) (io.ReadCloser, error)
|
||||
}
|
||||
|
||||
func (m *MockPdfGenerator) HtmlToPdf(html string) (io.ReadCloser, error) {
|
||||
if m.HtmlToPdfFunc != nil {
|
||||
return m.HtmlToPdfFunc(html)
|
||||
}
|
||||
return nil, errors.New("HtmlToPdfFunc not implemented")
|
||||
}
|
||||
|
||||
func TestGenerate(t *testing.T) {
|
||||
creditor := model.Entity{
|
||||
Name: "creditor",
|
||||
}
|
||||
deptor := model.Entity{
|
||||
Name: "deptor",
|
||||
}
|
||||
rate := 100.0
|
||||
repos := []Repo{
|
||||
{Owner: "owner", Repo: "repo"},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
setupMocks func(*MockGiteaClient, *MockPdfGenerator)
|
||||
config *Options
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "successful generation",
|
||||
setupMocks: func(g *MockGiteaClient, p *MockPdfGenerator) {
|
||||
g.ListRepoIssuesFunc = func(owner, repo string, opt gitea.ListIssueOption) ([]*gitea.Issue, *gitea.Response, error) {
|
||||
return []*gitea.Issue{
|
||||
{ID: 1, Title: "Test Issue", Body: "```info\nduration: 1h\n```"},
|
||||
}, &gitea.Response{}, nil
|
||||
}
|
||||
p.HtmlToPdfFunc = func(html string) (io.ReadCloser, error) {
|
||||
return io.NopCloser(bytes.NewReader([]byte("pdf"))), nil
|
||||
}
|
||||
},
|
||||
config: &DefaultOptions,
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "gitea error",
|
||||
setupMocks: func(g *MockGiteaClient, p *MockPdfGenerator) {
|
||||
g.ListRepoIssuesFunc = func(owner, repo string, opt gitea.ListIssueOption) ([]*gitea.Issue, *gitea.Response, error) {
|
||||
return nil, nil, errors.New("gitea error")
|
||||
}
|
||||
},
|
||||
config: &DefaultOptions,
|
||||
expectedError: "gitea error",
|
||||
},
|
||||
{
|
||||
name: "pdf error",
|
||||
setupMocks: func(g *MockGiteaClient, p *MockPdfGenerator) {
|
||||
g.ListRepoIssuesFunc = func(owner, repo string, opt gitea.ListIssueOption) ([]*gitea.Issue, *gitea.Response, error) {
|
||||
return []*gitea.Issue{
|
||||
{ID: 1, Title: "Test Issue", Body: "```info\nduration: 1h\n```"},
|
||||
}, &gitea.Response{}, nil
|
||||
}
|
||||
p.HtmlToPdfFunc = func(html string) (io.ReadCloser, error) {
|
||||
return nil, errors.New("pdf error")
|
||||
}
|
||||
},
|
||||
config: &DefaultOptions,
|
||||
expectedError: "pdf error",
|
||||
},
|
||||
{
|
||||
name: "no issues",
|
||||
setupMocks: func(g *MockGiteaClient, p *MockPdfGenerator) {
|
||||
g.ListRepoIssuesFunc = func(owner, repo string, opt gitea.ListIssueOption) ([]*gitea.Issue, *gitea.Response, error) {
|
||||
return []*gitea.Issue{}, &gitea.Response{}, nil
|
||||
}
|
||||
p.HtmlToPdfFunc = func(html string) (io.ReadCloser, error) {
|
||||
return io.NopCloser(bytes.NewReader([]byte("pdf"))), nil
|
||||
}
|
||||
},
|
||||
config: &DefaultOptions,
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "custom template",
|
||||
setupMocks: func(g *MockGiteaClient, p *MockPdfGenerator) {
|
||||
g.ListRepoIssuesFunc = func(owner, repo string, opt gitea.ListIssueOption) ([]*gitea.Issue, *gitea.Response, error) {
|
||||
return []*gitea.Issue{
|
||||
{ID: 1, Title: "Test Issue", Body: "```info\nduration: 1h\n```"},
|
||||
}, &gitea.Response{}, nil
|
||||
}
|
||||
p.HtmlToPdfFunc = func(html string) (io.ReadCloser, error) {
|
||||
return io.NopCloser(bytes.NewReader([]byte("pdf"))), nil
|
||||
}
|
||||
},
|
||||
config: &Options{
|
||||
Mindur: time.Minute * 15,
|
||||
Since: time.Now().AddDate(0, -1, 0),
|
||||
Before: time.Now(),
|
||||
IssueState: gitea.StateClosed,
|
||||
IssueFilter: func(i *gitea.Issue) bool { return true },
|
||||
CustomTemplate: "custom template",
|
||||
},
|
||||
expectedError: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
giteaClient := new(MockGiteaClient)
|
||||
|
||||
pdfGenerator := new(MockPdfGenerator)
|
||||
tc.setupMocks(giteaClient, pdfGenerator)
|
||||
|
||||
service := New(slog.Default(), giteaClient, pdfGenerator)
|
||||
doc, _, err := service.Generate(creditor, &deptor, rate, repos, tc.config)
|
||||
|
||||
if tc.expectedError != "" {
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error, but got none")
|
||||
}
|
||||
if !strings.Contains(err.Error(), tc.expectedError) {
|
||||
t.Errorf("expected error to contain '%s', but got '%s'", tc.expectedError, err.Error())
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, but got: %v", err)
|
||||
}
|
||||
if doc == nil {
|
||||
t.Fatal("expected a document, but got nil")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user