Skip to content

Commit

Permalink
Merge pull request #217 from PDOK/mapsheets-test
Browse files Browse the repository at this point in the history
Add test for features as mapsheets
  • Loading branch information
rkettelerij authored Jul 15, 2024
2 parents b951b7c + 02fa6e3 commit 0fdbf46
Show file tree
Hide file tree
Showing 11 changed files with 395 additions and 98 deletions.
90 changes: 0 additions & 90 deletions internal/engine/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,42 +9,17 @@ import (
"path/filepath"
"strings"
texttemplate "text/template"
"time"

"github.com/PDOK/gokoala/config"
"github.com/docker/go-units"

"github.com/PDOK/gokoala/internal/engine/util"
sprig "github.com/go-task/slim-sprig"
gomarkdown "github.com/gomarkdown/markdown"
gomarkdownhtml "github.com/gomarkdown/markdown/html"
gomarkdownparser "github.com/gomarkdown/markdown/parser"
"github.com/nicksnyder/go-i18n/v2/i18n"
stripmd "github.com/writeas/go-strip-markdown/v2"
"golang.org/x/text/language"
)

const (
layoutFile = "layout.go.html"
)

var (
globalTemplateFuncs texttemplate.FuncMap
)

func init() {
customFuncs := texttemplate.FuncMap{
// custom template functions
"markdown": markdown,
"unmarkdown": unmarkdown,
"humansize": humanSize,
"bytessize": bytesSize,
"isdate": isDate,
}
sprigFuncs := sprig.FuncMap() // we also support https://github.com/go-task/slim-sprig functions
globalTemplateFuncs = combineFuncMaps(customFuncs, sprigFuncs)
}

// TemplateKey unique key to register and lookup Go templates
type TemplateKey struct {
// Name of the template, the filename including extension
Expand Down Expand Up @@ -265,68 +240,3 @@ func (t *Templates) createTemplateFuncs(lang language.Tag) map[string]any {
},
})
}

// combine given FuncMaps
func combineFuncMaps(funcMaps ...map[string]any) map[string]any {
result := make(map[string]any)
for _, funcMap := range funcMaps {
for k, v := range funcMap {
result[k] = v
}
}
return result
}

// markdown turn Markdown into HTML
func markdown(s *string) htmltemplate.HTML {
if s == nil {
return ""
}
// always normalize newlines, this library only supports Unix LF newlines
md := gomarkdown.NormalizeNewlines([]byte(*s))

// create Markdown parser
extensions := gomarkdownparser.CommonExtensions
parser := gomarkdownparser.NewWithExtensions(extensions)

// parse Markdown into AST tree
doc := parser.Parse(md)

// create HTML renderer
htmlFlags := gomarkdownhtml.CommonFlags | gomarkdownhtml.HrefTargetBlank | gomarkdownhtml.SkipHTML
renderer := gomarkdownhtml.NewRenderer(gomarkdownhtml.RendererOptions{Flags: htmlFlags})

return htmltemplate.HTML(gomarkdown.Render(doc, renderer)) //nolint:gosec
}

// unmarkdown remove Markdown, so we can use the given string in non-HTML (JSON) output
func unmarkdown(s *string) string {
if s == nil {
return ""
}
withoutMarkdown := stripmd.Strip(*s)
withoutLinebreaks := strings.ReplaceAll(withoutMarkdown, "\n", " ")
return withoutLinebreaks
}

// humanSize converts size in bytes to a human-readable size
func humanSize(i int64) string {
return units.HumanSize(float64(i))
}

// bytesSize converts human-readable size to size in bytes (base-10, not base-2)
func bytesSize(s string) int64 {
i, err := units.FromHumanSize(s)
if err != nil {
log.Printf("cannot convert '%s' to bytes", s)
return 0
}
return i
}

func isDate(v any) bool {
if _, ok := v.(time.Time); ok {
return true
}
return false
}
113 changes: 113 additions & 0 deletions internal/engine/templatefuncs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package engine

import (
htmltemplate "html/template"
"log"
"strconv"
"strings"
texttemplate "text/template"
"time"

"github.com/docker/go-units"

sprig "github.com/go-task/slim-sprig"
gomarkdown "github.com/gomarkdown/markdown"
gomarkdownhtml "github.com/gomarkdown/markdown/html"
gomarkdownparser "github.com/gomarkdown/markdown/parser"
stripmd "github.com/writeas/go-strip-markdown/v2"
)

var (
globalTemplateFuncs texttemplate.FuncMap
)

// Initialize functions to be used in html/json/etc templates
func init() {
customFuncs := texttemplate.FuncMap{
// custom template functions
"markdown": markdown,
"unmarkdown": unmarkdown,
"humansize": humanSize,
"bytessize": bytesSize,
"isdate": isDate,
}
sprigFuncs := sprig.FuncMap() // we also support https://github.com/go-task/slim-sprig functions
globalTemplateFuncs = combineFuncMaps(customFuncs, sprigFuncs)
}

// combine given FuncMaps
func combineFuncMaps(funcMaps ...map[string]any) map[string]any {
result := make(map[string]any)
for _, funcMap := range funcMaps {
for k, v := range funcMap {
result[k] = v
}
}
return result
}

// markdown turn Markdown into HTML
func markdown(s *string) htmltemplate.HTML {
if s == nil {
return ""
}
// always normalize newlines, this library only supports Unix LF newlines
md := gomarkdown.NormalizeNewlines([]byte(*s))

// create Markdown parser
extensions := gomarkdownparser.CommonExtensions
parser := gomarkdownparser.NewWithExtensions(extensions)

// parse Markdown into AST tree
doc := parser.Parse(md)

// create HTML renderer
htmlFlags := gomarkdownhtml.CommonFlags | gomarkdownhtml.HrefTargetBlank | gomarkdownhtml.SkipHTML
renderer := gomarkdownhtml.NewRenderer(gomarkdownhtml.RendererOptions{Flags: htmlFlags})

return htmltemplate.HTML(gomarkdown.Render(doc, renderer)) //nolint:gosec
}

// unmarkdown remove Markdown, so we can use the given string in non-HTML (JSON) output
func unmarkdown(s *string) string {
if s == nil {
return ""
}
withoutMarkdown := stripmd.Strip(*s)
withoutLinebreaks := strings.ReplaceAll(withoutMarkdown, "\n", " ")
return withoutLinebreaks
}

// humanSize converts size in bytes to a human-readable size
func humanSize(a any) string {
if i, ok := a.(int64); ok {
return units.HumanSize(float64(i))
} else if f, ok := a.(float64); ok {
return units.HumanSize(f)
} else if s, ok := a.(string); ok {
fs, err := strconv.ParseFloat(s, 64)
if err == nil {
return units.HumanSize(fs)
}
}
log.Printf("cannot convert '%v' to float", a)
return "0"
}

// bytesSize converts human-readable size to size in bytes (base-10, not base-2)
func bytesSize(s string) int64 {
i, err := units.FromHumanSize(s)
if err != nil {
log.Printf("cannot convert '%s' to bytes", s)
return 0
}
return i
}

// isDate true when given input is a date, false otherwise
func isDate(v any) bool {
if _, ok := v.(time.Time); ok {
return true
}
return false
}
104 changes: 104 additions & 0 deletions internal/engine/templatefuncs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package engine

import (
"html/template"
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestMarkdown(t *testing.T) {
tests := []struct {
input *string
expected template.HTML
}{
{nil, ""},
{ptrTo("**bold**"), "<p><strong>bold</strong></p>\n"},
{ptrTo("# Heading"), "<h1>Heading</h1>\n"},
{ptrTo("Some [link](https://example.com)"), "<p>Some <a href=\"https://example.com\" target=\"_blank\">link</a></p>\n"},
}

for _, tt := range tests {
t.Run("", func(t *testing.T) {
assert.Equal(t, tt.expected, markdown(tt.input))
})
}
}

func TestUnmarkdown(t *testing.T) {
tests := []struct {
input *string
expected string
}{
{nil, ""},
{ptrTo("**bold**"), "bold"},
{ptrTo("# Heading"), "Heading"},
{ptrTo("Some [link](https://example.com)"), "Some link"},
}

for _, tt := range tests {
t.Run("", func(t *testing.T) {
assert.Equal(t, tt.expected, unmarkdown(tt.input))
})
}
}

func TestHumanSize(t *testing.T) {
tests := []struct {
input any
expected string
}{
{int64(1000), "1kB"},
{float64(1000), "1kB"},
{1000.00, "1kB"},
{"1000", "1kB"},
{"1000000", "1MB"},
{"invalid", "0"},
}

for _, tt := range tests {
t.Run("", func(t *testing.T) {
assert.Equal(t, tt.expected, humanSize(tt.input))
})
}
}

func TestBytesSize(t *testing.T) {
tests := []struct {
input string
expected int64
}{
{"1 kB", 1000},
{"1 MB", 1000000},
{"1.1 GB", 1100000000},
{"invalid", 0},
}

for _, tt := range tests {
t.Run("", func(t *testing.T) {
assert.Equal(t, tt.expected, bytesSize(tt.input))
})
}
}

func TestIsDate(t *testing.T) {
tests := []struct {
input any
expected bool
}{
{time.Now(), true},
{"not a date", false},
{12345, false},
}

for _, tt := range tests {
t.Run("", func(t *testing.T) {
assert.Equal(t, tt.expected, isDate(tt.input))
})
}
}

func ptrTo(s string) *string {
return &s
}
32 changes: 30 additions & 2 deletions internal/ogc/features/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func init() {
}
}

func TestFeatures_CollectionContent(t *testing.T) {
func TestFeatures(t *testing.T) {
type fields struct {
configFile string
url string
Expand Down Expand Up @@ -78,7 +78,7 @@ func TestFeatures_CollectionContent(t *testing.T) {
name: "Request GeoJSON for 'foo' collection using limit of 2 and cursor to next page",
fields: fields{
configFile: "internal/ogc/features/testdata/config_features_bag.yaml",
url: "http://localhost:8080/collections/tunneldelen/items?f=json&cursor=Dv4%7CNwyr1Q&limit=2",
url: "http://localhost:8080/collections/tunneldelen/items?cursor=Dv4%7CNwyr1Q&limit=2",
collectionID: "foo",
contentCrs: "<" + domain.WGS84CrsURI + ">",
format: "json",
Expand Down Expand Up @@ -461,6 +461,34 @@ func TestFeatures_CollectionContent(t *testing.T) {
statusCode: http.StatusOK,
},
},
{
name: "Request mapsheets as JSON",
fields: fields{
configFile: "internal/ogc/features/testdata/config_mapsheets.yaml",
url: "http://localhost:8080/collections/:collectionId/items?limit=2",
collectionID: "example_mapsheets",
contentCrs: "<" + domain.WGS84CrsURI + ">",
format: "json",
},
want: want{
body: "internal/ogc/features/testdata/expected_mapsheets.json",
statusCode: http.StatusOK,
},
},
{
name: "Request mapsheets as HTML",
fields: fields{
configFile: "internal/ogc/features/testdata/config_mapsheets.yaml",
url: "http://localhost:8080/collections/:collectionId/items?limit=2",
collectionID: "example_mapsheets",
contentCrs: "<" + domain.WGS84CrsURI + ">",
format: "html",
},
want: want{
body: "internal/ogc/features/testdata/expected_mapsheets.html",
statusCode: http.StatusOK,
},
},
{
name: "Request slow response, hitting query timeout",
fields: fields{
Expand Down
Loading

0 comments on commit 0fdbf46

Please sign in to comment.