addressed consistency
This commit is contained in:
1 parent
3b971cda61
commit
ebb471524e
8 files changed
+99
-81
No files matched your search
@@ -15,8 +15,8 @@ import (
|
|||||||
"github.com/nmoniz/any2anexoj/internal/trading212"
|
"github.com/nmoniz/any2anexoj/internal/trading212"
|
||||||
"github.com/nmoniz/any2anexoj/internal/writing"
|
"github.com/nmoniz/any2anexoj/internal/writing"
|
||||||
"github.com/nmoniz/any2anexoj/internal/writing/csv"
|
"github.com/nmoniz/any2anexoj/internal/writing/csv"
|
||||||
"github.com/nmoniz/any2anexoj/internal/writing/html"
|
htmlwriter "github.com/nmoniz/any2anexoj/internal/writing/html"
|
||||||
"github.com/nmoniz/any2anexoj/internal/writing/pretty"
|
"github.com/nmoniz/any2anexoj/internal/writing/table"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
)
|
)
|
||||||
@@ -102,13 +102,13 @@ func runWithIO(ctx context.Context, stdin io.Reader, stdout io.Writer) error {
|
|||||||
|
|
||||||
switch *format {
|
switch *format {
|
||||||
case "csv":
|
case "csv":
|
||||||
return csv.NewCSVWriter(stdout).Render(writer)
|
return csv.NewWriter(stdout).Render(writer)
|
||||||
case "table":
|
case "table":
|
||||||
loc, err := writing.NewLocalizer(*lang)
|
loc, err := writing.NewLocalizer(*lang)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("create localizer: %w", err)
|
return fmt.Errorf("create localizer: %w", err)
|
||||||
}
|
}
|
||||||
pretty.NewPrettyPrinter(stdout, loc).Render(writer)
|
table.NewPrinter(stdout, loc).Render(writer)
|
||||||
return nil
|
return nil
|
||||||
case "html":
|
case "html":
|
||||||
loc, err := writing.NewLocalizer(*lang)
|
loc, err := writing.NewLocalizer(*lang)
|
||||||
@@ -117,9 +117,8 @@ func runWithIO(ctx context.Context, stdin io.Reader, stdout io.Writer) error {
|
|||||||
}
|
}
|
||||||
// RenderHTML never writes to the printer's output writer, so
|
// RenderHTML never writes to the printer's output writer, so
|
||||||
// io.Discard is safe here.
|
// io.Discard is safe here.
|
||||||
printer := pretty.NewPrettyPrinter(io.Discard, loc)
|
printer := table.NewPrinter(io.Discard, loc)
|
||||||
title := loc.Translate("report_title", 1, nil)
|
return htmlwriter.NewWriter(stdout, printer, loc, *lang).Render(writer)
|
||||||
return html.NewHTMLWriter(stdout, printer, title, *lang).Render(writer)
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported format %q: must be table, csv or html", *format)
|
return fmt.Errorf("unsupported format %q: must be table, csv or html", *format)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,15 +10,15 @@ import (
|
|||||||
"github.com/nmoniz/any2anexoj/internal"
|
"github.com/nmoniz/any2anexoj/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CSVWriter struct {
|
type Writer struct {
|
||||||
w *csv.Writer
|
w *csv.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCSVWriter(w io.Writer) *CSVWriter {
|
func NewWriter(w io.Writer) *Writer {
|
||||||
return &CSVWriter{w: csv.NewWriter(w)}
|
return &Writer{w: csv.NewWriter(w)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cw *CSVWriter) Render(aw *internal.AggregatorWriter) error {
|
func (cw *Writer) Render(aw *internal.AggregatorWriter) error {
|
||||||
err := cw.w.Write([]string{
|
err := cw.w.Write([]string{
|
||||||
"source_country", "code",
|
"source_country", "code",
|
||||||
"realization_year", "realization_month", "realization_day", "realization_value",
|
"realization_year", "realization_month", "realization_day", "realization_value",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCSVWriter_Render(t *testing.T) {
|
func TestWriter_Render(t *testing.T) {
|
||||||
aw := internal.NewAggregatorWriter()
|
aw := internal.NewAggregatorWriter()
|
||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ func TestCSVWriter_Render(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err := csv.NewCSVWriter(&buf).Render(aw); err != nil {
|
if err := csv.NewWriter(&buf).Render(aw); err != nil {
|
||||||
t.Fatalf("render: %v", err)
|
t.Fatalf("render: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="{{.Lang}}">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>{{.Title}}</title>
|
||||||
|
<link rel="stylesheet" href="{{.CSSURL}}" integrity="{{.Integrity}}" crossorigin="anonymous">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main class="container-fluid py-4">
|
||||||
|
<h1>{{.Title}}</h1>
|
||||||
|
<div class="table-responsive">
|
||||||
|
{{.TableFragment}}
|
||||||
|
</div>
|
||||||
|
<p class="text-muted small">Generated at {{.GeneratedAt}}</p>
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -1,79 +1,73 @@
|
|||||||
// Package html renders an internal.AggregatorWriter as a complete,
|
// Package html renders an internal.AggregatorWriter as a complete,
|
||||||
// standalone HTML document built around the same table fragment produced by
|
// standalone HTML document built around the same table fragment produced by
|
||||||
// pretty.PrettyPrinter.RenderHTML. The document includes the Bootstrap 5.3
|
// table.Printer.RenderHTML. The document includes the Bootstrap 5.3
|
||||||
// stylesheet via CDN and embeds the raw table fragment without HTML-escaping
|
// stylesheet via CDN and embeds the raw table fragment without HTML-escaping
|
||||||
// it so the result opens directly in a browser.
|
// it so the result opens directly in a browser.
|
||||||
package html
|
package html
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nmoniz/any2anexoj/internal"
|
"github.com/nmoniz/any2anexoj/internal"
|
||||||
"github.com/nmoniz/any2anexoj/internal/writing/pretty"
|
"github.com/nmoniz/any2anexoj/internal/writing/table"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// translator is the contract the HTML writer relies on for localized
|
||||||
|
// document text such as the page title. *writing.Localizer satisfies it.
|
||||||
|
type translator interface {
|
||||||
|
Translate(key string, count int, values map[string]any) string
|
||||||
|
}
|
||||||
|
|
||||||
// bootstrapCSSURL is the jsDelivr CDN URL for Bootstrap 5.3.3.
|
// bootstrapCSSURL is the jsDelivr CDN URL for Bootstrap 5.3.3.
|
||||||
const bootstrapCSSURL = "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
|
const bootstrapCSSURL = "https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
|
||||||
|
|
||||||
// bootstrapIntegrity is the official SRI hash for Bootstrap 5.3.3 css.
|
// bootstrapIntegrity is the official SRI hash for Bootstrap 5.3.3 css.
|
||||||
const bootstrapIntegrity = "sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
|
const bootstrapIntegrity = "sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
|
||||||
|
|
||||||
// HTMLWriter writes a complete HTML document for an AggregatorWriter.
|
// Writer writes a complete HTML document for an AggregatorWriter.
|
||||||
type HTMLWriter struct {
|
type Writer struct {
|
||||||
output io.Writer
|
output io.Writer
|
||||||
printer *pretty.PrettyPrinter
|
printer *table.Printer
|
||||||
title string
|
translator translator
|
||||||
lang string
|
lang string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewHTMLWriter builds an HTMLWriter that writes a complete HTML document to
|
// NewWriter builds a Writer that writes a complete HTML document to
|
||||||
// w. The printer is used purely as a source for the raw <table> fragment via
|
// w. The printer is used purely as a source for the raw <table> fragment via
|
||||||
// RenderHTML; this writer never invokes Render or any method that writes to
|
// RenderHTML; this writer never invokes Render or any method that writes to
|
||||||
// printer's own io.Writer.
|
// printer's own io.Writer. The document title is looked up from the
|
||||||
func NewHTMLWriter(w io.Writer, printer *pretty.PrettyPrinter, title, lang string) *HTMLWriter {
|
// "report_title" translation via tr, so callers never pass a pre-baked title.
|
||||||
return &HTMLWriter{
|
func NewWriter(w io.Writer, printer *table.Printer, tr translator, lang string) *Writer {
|
||||||
output: w,
|
return &Writer{
|
||||||
printer: printer,
|
output: w,
|
||||||
title: title,
|
printer: printer,
|
||||||
lang: lang,
|
translator: tr,
|
||||||
|
lang: lang,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentTemplate renders the full HTML page. The table fragment is typed as
|
//go:embed document.tmpl
|
||||||
// template.HTML so the template engine emits it verbatim without escaping
|
var documentTemplateBody string
|
||||||
// the angle brackets in the <table> markup.
|
|
||||||
var documentTemplate = template.Must(template.New("html").Parse(`<!DOCTYPE html>
|
// documentTemplate renders the full HTML page from document.tmpl. The table
|
||||||
<html lang="{{.Lang}}">
|
// fragment is typed as template.HTML so the template engine emits it
|
||||||
<head>
|
// verbatim without escaping the angle brackets in the <table> markup.
|
||||||
<meta charset="utf-8">
|
var documentTemplate = template.Must(template.New("html").Parse(documentTemplateBody))
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>{{.Title}}</title>
|
|
||||||
<link rel="stylesheet" href="{{.CSSURL}}" integrity="{{.Integrity}}" crossorigin="anonymous">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<main class="container-fluid py-4">
|
|
||||||
<h1>{{.Title}}</h1>
|
|
||||||
<div class="table-responsive">
|
|
||||||
{{.TableFragment}}
|
|
||||||
</div>
|
|
||||||
<p class="text-muted small">Generated at {{.GeneratedAt}}</p>
|
|
||||||
</main>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
`))
|
|
||||||
|
|
||||||
// Render writes a complete standalone HTML document for aw to the configured
|
// Render writes a complete standalone HTML document for aw to the configured
|
||||||
// output. The same HTMLWriter may be reused; each call rebuilds the table
|
// output. The same Writer may be reused; each call rebuilds the table
|
||||||
// fragment from aw so the rendered <tr> count reflects aw's current items and
|
// fragment from aw so the rendered <tr> count reflects aw's current items and
|
||||||
// no rows are duplicated across invocations.
|
// no rows are duplicated across invocations.
|
||||||
func (hw *HTMLWriter) Render(aw *internal.AggregatorWriter) error {
|
func (hw *Writer) Render(aw *internal.AggregatorWriter) error {
|
||||||
if hw.printer == nil {
|
if hw.printer == nil {
|
||||||
return fmt.Errorf("html: nil printer")
|
return fmt.Errorf("html: nil printer")
|
||||||
}
|
}
|
||||||
fragment := hw.printer.RenderHTML(aw)
|
fragment := hw.printer.RenderHTML(aw)
|
||||||
|
title := hw.translator.Translate("report_title", 1, nil)
|
||||||
data := struct {
|
data := struct {
|
||||||
Lang string
|
Lang string
|
||||||
Title string
|
Title string
|
||||||
@@ -83,7 +77,7 @@ func (hw *HTMLWriter) Render(aw *internal.AggregatorWriter) error {
|
|||||||
GeneratedAt string
|
GeneratedAt string
|
||||||
}{
|
}{
|
||||||
Lang: hw.lang,
|
Lang: hw.lang,
|
||||||
Title: hw.title,
|
Title: title,
|
||||||
CSSURL: bootstrapCSSURL,
|
CSSURL: bootstrapCSSURL,
|
||||||
Integrity: bootstrapIntegrity,
|
Integrity: bootstrapIntegrity,
|
||||||
TableFragment: template.HTML(fragment),
|
TableFragment: template.HTML(fragment),
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
htmlwriter "github.com/nmoniz/any2anexoj/internal/writing/html"
|
htmlwriter "github.com/nmoniz/any2anexoj/internal/writing/html"
|
||||||
"github.com/nmoniz/any2anexoj/internal/writing/pretty"
|
"github.com/nmoniz/any2anexoj/internal/writing/table"
|
||||||
"github.com/nmoniz/any2anexoj/internal/writing"
|
"github.com/nmoniz/any2anexoj/internal/writing"
|
||||||
"github.com/nmoniz/any2anexoj/internal"
|
"github.com/nmoniz/any2anexoj/internal"
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
// buildTestAggregator returns an AggregatorWriter seeded with two
|
// buildTestAggregator returns an AggregatorWriter seeded with two
|
||||||
// deterministic ReportItems so every test can assert on a stable document
|
// deterministic ReportItems so every test can assert on a stable document
|
||||||
// shape. Mirrors the fixture pattern used in
|
// shape. Mirrors the fixture pattern used in
|
||||||
// internal/writing/pretty/printer_test.go.
|
// internal/writing/table/printer_test.go.
|
||||||
func buildTestAggregator(t *testing.T) *internal.AggregatorWriter {
|
func buildTestAggregator(t *testing.T) *internal.AggregatorWriter {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
aw := internal.NewAggregatorWriter()
|
aw := internal.NewAggregatorWriter()
|
||||||
@@ -57,7 +57,7 @@ func buildTestAggregator(t *testing.T) *internal.AggregatorWriter {
|
|||||||
return aw
|
return aw
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHTMLWriter_Render(t *testing.T) {
|
func TestWriter_Render(t *testing.T) {
|
||||||
loc, err := writing.NewLocalizer("en")
|
loc, err := writing.NewLocalizer("en")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("create localizer: %v", err)
|
t.Fatalf("create localizer: %v", err)
|
||||||
@@ -65,8 +65,8 @@ func TestHTMLWriter_Render(t *testing.T) {
|
|||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
// RenderHTML never writes to the printer's output, so Discard is safe.
|
// RenderHTML never writes to the printer's output, so Discard is safe.
|
||||||
pp := pretty.NewPrettyPrinter(&buf, loc)
|
pp := table.NewPrinter(&buf, loc)
|
||||||
hw := htmlwriter.NewHTMLWriter(&buf, pp, "Tax report", "en")
|
hw := htmlwriter.NewWriter(&buf, pp, loc, "en")
|
||||||
|
|
||||||
if err := hw.Render(buildTestAggregator(t)); err != nil {
|
if err := hw.Render(buildTestAggregator(t)); err != nil {
|
||||||
t.Fatalf("Render returned an error: %v", err)
|
t.Fatalf("Render returned an error: %v", err)
|
||||||
@@ -123,18 +123,18 @@ func TestHTMLWriter_Render(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestHTMLWriter_NoRowDuplication verifies that calling Render twice on the
|
// TestWriter_NoRowDuplication verifies that calling Render twice on the
|
||||||
// same writer produces documents with the same number of <tr> rows, just
|
// same writer produces documents with the same number of <tr> rows, just
|
||||||
// like pretty.PrettyPrinter's no-duplication guarantee.
|
// like table.Printer's no-duplication guarantee.
|
||||||
func TestHTMLWriter_NoRowDuplication(t *testing.T) {
|
func TestWriter_NoRowDuplication(t *testing.T) {
|
||||||
loc, err := writing.NewLocalizer("en")
|
loc, err := writing.NewLocalizer("en")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("create localizer: %v", err)
|
t.Fatalf("create localizer: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
pp := pretty.NewPrettyPrinter(&buf, loc)
|
pp := table.NewPrinter(&buf, loc)
|
||||||
hw := htmlwriter.NewHTMLWriter(&buf, pp, "Tax report", "en")
|
hw := htmlwriter.NewWriter(&buf, pp, loc, "en")
|
||||||
|
|
||||||
aw := buildTestAggregator(t)
|
aw := buildTestAggregator(t)
|
||||||
|
|
||||||
@@ -160,15 +160,15 @@ func TestHTMLWriter_NoRowDuplication(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHTMLWriter_LangAttribute(t *testing.T) {
|
func TestWriter_LangAttribute(t *testing.T) {
|
||||||
loc, err := writing.NewLocalizer("pt")
|
loc, err := writing.NewLocalizer("pt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("create localizer: %v", err)
|
t.Fatalf("create localizer: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
pp := pretty.NewPrettyPrinter(&buf, loc)
|
pp := table.NewPrinter(&buf, loc)
|
||||||
hw := htmlwriter.NewHTMLWriter(&buf, pp, "Relatório fiscal", "pt")
|
hw := htmlwriter.NewWriter(&buf, pp, loc, "pt")
|
||||||
|
|
||||||
if err := hw.Render(buildTestAggregator(t)); err != nil {
|
if err := hw.Render(buildTestAggregator(t)); err != nil {
|
||||||
t.Fatalf("Render returned an error: %v", err)
|
t.Fatalf("Render returned an error: %v", err)
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// Package table renders an internal.AggregatorWriter as the human-readable
|
||||||
|
// Anexo J report table, for the terminal (Render) and for embedding in HTML
|
||||||
|
// documents (RenderHTML).
|
||||||
package table
|
package table
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -10,22 +13,22 @@ import (
|
|||||||
"github.com/nmoniz/any2anexoj/internal"
|
"github.com/nmoniz/any2anexoj/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
// translator is the contract the pretty printer relies on for human-readable
|
// translator is the contract the table printer relies on for human-readable
|
||||||
// column labels. *Localizer satisfies it.
|
// column labels. *Localizer satisfies it.
|
||||||
type translator interface {
|
type translator interface {
|
||||||
Translate(key string, count int, values map[string]any) string
|
Translate(key string, count int, values map[string]any) string
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrettyPrinter writes a simple, human readable, table row to the provided io.Writer for each
|
// Printer writes a simple, human readable, table row to the provided io.Writer for each
|
||||||
// ReportItem received. Render and RenderHTML each build a fresh table.Writer so that
|
// ReportItem received. Render and RenderHTML each build a fresh table.Writer so that
|
||||||
// invoking them (in any order or repeatedly) on the same instance never duplicates rows.
|
// invoking them (in any order or repeatedly) on the same instance never duplicates rows.
|
||||||
type PrettyPrinter struct {
|
type Printer struct {
|
||||||
output io.Writer
|
output io.Writer
|
||||||
translator translator
|
translator translator
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPrettyPrinter(w io.Writer, tr translator) *PrettyPrinter {
|
func NewPrinter(w io.Writer, tr translator) *Printer {
|
||||||
return &PrettyPrinter{
|
return &Printer{
|
||||||
output: w,
|
output: w,
|
||||||
translator: tr,
|
translator: tr,
|
||||||
}
|
}
|
||||||
@@ -36,7 +39,7 @@ func NewPrettyPrinter(w io.Writer, tr translator) *PrettyPrinter {
|
|||||||
// multiple times without duplicating rows. The returned table is not wired to
|
// multiple times without duplicating rows. The returned table is not wired to
|
||||||
// pp.output via an output mirror; callers that want the rendered output
|
// pp.output via an output mirror; callers that want the rendered output
|
||||||
// written to pp.output must set the mirror themselves before calling .Render().
|
// written to pp.output must set the mirror themselves before calling .Render().
|
||||||
func (pp *PrettyPrinter) buildTable(aw *internal.AggregatorWriter) table.Writer {
|
func (pp *Printer) buildTable(aw *internal.AggregatorWriter) table.Writer {
|
||||||
tw := table.NewWriter()
|
tw := table.NewWriter()
|
||||||
tw.SetAutoIndex(true)
|
tw.SetAutoIndex(true)
|
||||||
tw.SetStyle(table.StyleLight)
|
tw.SetStyle(table.StyleLight)
|
||||||
@@ -81,12 +84,16 @@ func (pp *PrettyPrinter) buildTable(aw *internal.AggregatorWriter) table.Writer
|
|||||||
}
|
}
|
||||||
|
|
||||||
sumTxt := pp.translator.Translate("sum", 1, nil)
|
sumTxt := pp.translator.Translate("sum", 1, nil)
|
||||||
tw.AppendFooter(table.Row{sumTxt, sumTxt, sumTxt, sumTxt, sumTxt, aw.TotalEarned(), "", "", "", aw.TotalSpent(), aw.TotalFees(), aw.TotalTaxes()}, table.RowConfig{AutoMerge: true, AutoMergeAlign: text.AlignRight})
|
// The footer lists one cell per column (13) so it never relies on
|
||||||
|
// go-pretty's implicit short-row padding; the trailing empty cell is the
|
||||||
|
// counter-country column, which has no total. Totals are formatted with
|
||||||
|
// StringFixed(2) so they match the two-decimal data rows.
|
||||||
|
tw.AppendFooter(table.Row{sumTxt, sumTxt, sumTxt, sumTxt, sumTxt, aw.TotalEarned().StringFixed(2), "", "", "", aw.TotalSpent().StringFixed(2), aw.TotalFees().StringFixed(2), aw.TotalTaxes().StringFixed(2), ""}, table.RowConfig{AutoMerge: true, AutoMergeAlign: text.AlignRight})
|
||||||
|
|
||||||
return tw
|
return tw
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *PrettyPrinter) Render(aw *internal.AggregatorWriter) {
|
func (pp *Printer) Render(aw *internal.AggregatorWriter) {
|
||||||
t := pp.buildTable(aw)
|
t := pp.buildTable(aw)
|
||||||
t.SetOutputMirror(pp.output)
|
t.SetOutputMirror(pp.output)
|
||||||
t.Render()
|
t.Render()
|
||||||
@@ -94,7 +101,7 @@ func (pp *PrettyPrinter) Render(aw *internal.AggregatorWriter) {
|
|||||||
|
|
||||||
// RenderHTML builds a fresh table from aw and renders it as an HTML string
|
// RenderHTML builds a fresh table from aw and renders it as an HTML string
|
||||||
// using go-pretty's HTMLOptions.
|
// using go-pretty's HTMLOptions.
|
||||||
func (pp *PrettyPrinter) RenderHTML(aw *internal.AggregatorWriter) string {
|
func (pp *Printer) RenderHTML(aw *internal.AggregatorWriter) string {
|
||||||
t := pp.buildTable(aw)
|
t := pp.buildTable(aw)
|
||||||
t.Style().HTML = table.HTMLOptions{
|
t.Style().HTML = table.HTMLOptions{
|
||||||
CSSClass: "table table-striped table-hover table-bordered",
|
CSSClass: "table table-striped table-hover table-bordered",
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPrettyPrinter_Render(t *testing.T) {
|
func TestPrinter_Render(t *testing.T) {
|
||||||
// Create test data
|
// Create test data
|
||||||
aw := internal.NewAggregatorWriter()
|
aw := internal.NewAggregatorWriter()
|
||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
@@ -58,7 +58,7 @@ func TestPrettyPrinter_Render(t *testing.T) {
|
|||||||
|
|
||||||
// Create writing printer with buffer
|
// Create writing printer with buffer
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
pp := table.NewPrettyPrinter(&buf, localizer)
|
pp := table.NewPrinter(&buf, localizer)
|
||||||
|
|
||||||
// Render the table
|
// Render the table
|
||||||
pp.Render(aw)
|
pp.Render(aw)
|
||||||
@@ -75,13 +75,13 @@ func TestPrettyPrinter_Render(t *testing.T) {
|
|||||||
│ 1 │ 840 - United States │ G01 │ 2023 │ 6 │ 20 │ 150.75 € │ 2023 │ 1 │ 15 │ 100.50 € │ 2.50 € │ 5.00 € │ 826 - United Kingdom │
|
│ 1 │ 840 - United States │ G01 │ 2023 │ 6 │ 20 │ 150.75 € │ 2023 │ 1 │ 15 │ 100.50 € │ 2.50 € │ 5.00 € │ 826 - United Kingdom │
|
||||||
│ 2 │ 840 - United States │ G20 │ 2023 │ 9 │ 5 │ 225.50 € │ 2023 │ 3 │ 10 │ 200.00 € │ 3.00 € │ 7.50 € │ 826 - United Kingdom │
|
│ 2 │ 840 - United States │ G20 │ 2023 │ 9 │ 5 │ 225.50 € │ 2023 │ 3 │ 10 │ 200.00 € │ 3.00 € │ 7.50 € │ 826 - United Kingdom │
|
||||||
├───┼─────────────────────┴──────┴──────┴───────┴─────┼──────────────┼──────┴───────┴─────┼──────────────┼─────────────────┼─────────────────┼──────────────────────┤
|
├───┼─────────────────────┴──────┴──────┴───────┴─────┼──────────────┼──────┴───────┴─────┼──────────────┼─────────────────┼─────────────────┼──────────────────────┤
|
||||||
│ │ SUM │ 376.25 € │ │ 300.5 € │ 5.5 € │ 12.5 € │ │
|
│ │ SUM │ 376.25 € │ │ 300.50 € │ 5.50 € │ 12.50 € │ │
|
||||||
└───┴─────────────────────────────────────────────────┴──────────────┴────────────────────┴──────────────┴─────────────────┴─────────────────┴──────────────────────┘
|
└───┴─────────────────────────────────────────────────┴──────────────┴────────────────────┴──────────────┴─────────────────┴─────────────────┴──────────────────────┘
|
||||||
`
|
`
|
||||||
|
|
||||||
// Compare output
|
// Compare output
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Errorf("PrettyPrinter.Render() output doesn't match expected.\n\nGot:\n%s\n\nWant:\n%s", got, want)
|
t.Errorf("Printer.Render() output doesn't match expected.\n\nGot:\n%s\n\nWant:\n%s", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ func TestRenderHTML(t *testing.T) {
|
|||||||
// Output buffer used only to satisfy the constructor contract; RenderHTML
|
// Output buffer used only to satisfy the constructor contract; RenderHTML
|
||||||
// must not write to it.
|
// must not write to it.
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
pp := table.NewPrettyPrinter(&buf, localizer)
|
pp := table.NewPrinter(&buf, localizer)
|
||||||
|
|
||||||
html := pp.RenderHTML(aw)
|
html := pp.RenderHTML(aw)
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user