mirror of
https://github.com/terraform-docs/terraform-docs.git
synced 2026-03-27 04:48:33 +07:00
<br /> provides additional support for XHTML without breaking compatibility with HTML. This can be useful when trying to publish documentation generated by terraform-docs to XHTML based solutions Signed-off-by: christophe.vandekerchove <christophe.vandekerchove@scalepad.com>
559 lines
13 KiB
Go
559 lines
13 KiB
Go
/*
|
|
Copyright 2021 The terraform-docs Authors.
|
|
|
|
Licensed under the MIT license (the "License"); you may not
|
|
use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at the LICENSE file in
|
|
the root directory of this source tree.
|
|
*/
|
|
|
|
package template
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
gotemplate "text/template"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/terraform-docs/terraform-docs/internal/types"
|
|
"github.com/terraform-docs/terraform-docs/print"
|
|
"github.com/terraform-docs/terraform-docs/terraform"
|
|
)
|
|
|
|
func TestTemplateRender(t *testing.T) {
|
|
sectionTpl := `
|
|
{{- with .Module.Header -}}
|
|
{{ custom . }}
|
|
{{- end -}}
|
|
`
|
|
customFuncs := gotemplate.FuncMap{
|
|
"custom": func(s string) string {
|
|
return fmt.Sprintf("customized <<%s>>", s)
|
|
},
|
|
}
|
|
module := &terraform.Module{
|
|
Header: "sample header",
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
items []*Item
|
|
expected string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "template render with custom functions",
|
|
items: []*Item{
|
|
{
|
|
Name: "all",
|
|
Text: `{{- template "section" . -}}`,
|
|
}, {
|
|
Name: "section",
|
|
Text: sectionTpl,
|
|
},
|
|
},
|
|
expected: "customized <<sample header>>",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "template render with custom functions",
|
|
items: []*Item{},
|
|
expected: "",
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert := assert.New(t)
|
|
tpl := New(print.DefaultConfig(), tt.items...)
|
|
tpl.CustomFunc(customFuncs)
|
|
rendered, err := tpl.Render("", module)
|
|
if tt.wantErr {
|
|
assert.NotNil(err)
|
|
} else {
|
|
assert.Nil(err)
|
|
assert.Equal(tt.expected, rendered)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuiltinFunc(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
funcName string
|
|
funcArgs []string
|
|
escape bool
|
|
expected string
|
|
}{
|
|
// default
|
|
{
|
|
name: "template builtin functions default",
|
|
funcName: "default",
|
|
funcArgs: []string{`"a"`, `"b"`},
|
|
escape: true,
|
|
expected: "b",
|
|
},
|
|
{
|
|
name: "template builtin functions default",
|
|
funcName: "default",
|
|
funcArgs: []string{`"a"`, `""`},
|
|
escape: true,
|
|
expected: "a",
|
|
},
|
|
{
|
|
name: "template builtin functions default",
|
|
funcName: "default",
|
|
funcArgs: []string{`""`, `"b"`},
|
|
escape: true,
|
|
expected: "b",
|
|
},
|
|
{
|
|
name: "template builtin functions default",
|
|
funcName: "default",
|
|
funcArgs: []string{`""`, `""`},
|
|
escape: true,
|
|
expected: "",
|
|
},
|
|
|
|
// tostring
|
|
{
|
|
name: "template builtin functions tostring",
|
|
funcName: "tostring",
|
|
funcArgs: []string{`"foo"`},
|
|
escape: true,
|
|
expected: "foo",
|
|
},
|
|
{
|
|
name: "template builtin functions tostring",
|
|
funcName: "tostring",
|
|
funcArgs: []string{`""`},
|
|
escape: true,
|
|
expected: "",
|
|
},
|
|
|
|
// trim
|
|
{
|
|
name: "template builtin functions trim",
|
|
funcName: "trim",
|
|
funcArgs: []string{`" "`, `" foo "`},
|
|
escape: true,
|
|
expected: "foo",
|
|
},
|
|
{
|
|
name: "template builtin functions trim",
|
|
funcName: "trim",
|
|
funcArgs: []string{`" "`, `"foo"`},
|
|
escape: true,
|
|
expected: "foo",
|
|
},
|
|
{
|
|
name: "template builtin functions trim",
|
|
funcName: "trim",
|
|
funcArgs: []string{`""`, `"foo"`},
|
|
escape: true,
|
|
expected: "foo",
|
|
},
|
|
{
|
|
name: "template builtin functions trim",
|
|
funcName: "trim",
|
|
funcArgs: []string{`" "`, `""`},
|
|
escape: true,
|
|
expected: "",
|
|
},
|
|
|
|
// trimLeft
|
|
{
|
|
name: "template builtin functions trimLeft",
|
|
funcName: "trimLeft",
|
|
funcArgs: []string{`" "`, `" foo "`},
|
|
escape: true,
|
|
expected: "foo ",
|
|
},
|
|
{
|
|
name: "template builtin functions trimLeft",
|
|
funcName: "trimLeft",
|
|
funcArgs: []string{`" "`, `"foo"`},
|
|
escape: true,
|
|
expected: "foo",
|
|
},
|
|
{
|
|
name: "template builtin functions trimLeft",
|
|
funcName: "trimLeft",
|
|
funcArgs: []string{`""`, `"foo"`},
|
|
escape: true,
|
|
expected: "foo",
|
|
},
|
|
{
|
|
name: "template builtin functions trimLeft",
|
|
funcName: "trimLeft",
|
|
funcArgs: []string{`" "`, `""`},
|
|
escape: true,
|
|
expected: "",
|
|
},
|
|
|
|
// trimRight
|
|
{
|
|
name: "template builtin functions trimRight",
|
|
funcName: "trimRight",
|
|
funcArgs: []string{`" "`, `" foo "`},
|
|
escape: true,
|
|
expected: " foo",
|
|
},
|
|
{
|
|
name: "template builtin functions trimRight",
|
|
funcName: "trimRight",
|
|
funcArgs: []string{`" "`, `"foo"`},
|
|
escape: true,
|
|
expected: "foo",
|
|
},
|
|
{
|
|
name: "template builtin functions trimRight",
|
|
funcName: "trimRight",
|
|
funcArgs: []string{`""`, `"foo"`},
|
|
escape: true,
|
|
expected: "foo",
|
|
},
|
|
{
|
|
name: "template builtin functions trimRight",
|
|
funcName: "trimRight",
|
|
funcArgs: []string{`" "`, `""`},
|
|
escape: true,
|
|
expected: "",
|
|
},
|
|
|
|
// trimPrefix
|
|
{
|
|
name: "template builtin functions trimPrefix",
|
|
funcName: "trimPrefix",
|
|
funcArgs: []string{`" "`, `" foo "`},
|
|
escape: true,
|
|
expected: " foo ",
|
|
},
|
|
{
|
|
name: "template builtin functions trimPrefix",
|
|
funcName: "trimPrefix",
|
|
funcArgs: []string{`" "`, `"foo"`},
|
|
escape: true,
|
|
expected: "foo",
|
|
},
|
|
{
|
|
name: "template builtin functions trimPrefix",
|
|
funcName: "trimPrefix",
|
|
funcArgs: []string{`""`, `"foo"`},
|
|
escape: true,
|
|
expected: "foo",
|
|
},
|
|
{
|
|
name: "template builtin functions trimPrefix",
|
|
funcName: "trimPrefix",
|
|
funcArgs: []string{`" "`, `""`},
|
|
escape: true,
|
|
expected: "",
|
|
},
|
|
|
|
// trimSuffix
|
|
{
|
|
name: "template builtin functions trimSuffix",
|
|
funcName: "trimSuffix",
|
|
funcArgs: []string{`" "`, `" foo "`},
|
|
escape: true,
|
|
expected: " foo ",
|
|
},
|
|
{
|
|
name: "template builtin functions trimSuffix",
|
|
funcName: "trimSuffix",
|
|
funcArgs: []string{`" "`, `"foo"`},
|
|
escape: true,
|
|
expected: "foo",
|
|
},
|
|
{
|
|
name: "template builtin functions trimSuffix",
|
|
funcName: "trimSuffix",
|
|
funcArgs: []string{`""`, `"foo"`},
|
|
escape: true,
|
|
expected: "foo",
|
|
},
|
|
{
|
|
name: "template builtin functions trimSuffix",
|
|
funcName: "trimSuffix",
|
|
funcArgs: []string{`" "`, `""`},
|
|
escape: true,
|
|
expected: "",
|
|
},
|
|
|
|
// indent
|
|
{
|
|
name: "template builtin functions indent",
|
|
funcName: "indent",
|
|
funcArgs: []string{`0`, `"#"`},
|
|
escape: true,
|
|
expected: "##",
|
|
},
|
|
{
|
|
name: "template builtin functions indent",
|
|
funcName: "indent",
|
|
funcArgs: []string{`1`, `"#"`},
|
|
escape: true,
|
|
expected: "###",
|
|
},
|
|
{
|
|
name: "template builtin functions indent",
|
|
funcName: "indent",
|
|
funcArgs: []string{`2`, `"#"`},
|
|
escape: true,
|
|
expected: "####",
|
|
},
|
|
{
|
|
name: "template builtin functions indent",
|
|
funcName: "indent",
|
|
funcArgs: []string{`3`, `"#"`},
|
|
escape: true,
|
|
expected: "#####",
|
|
},
|
|
|
|
// name
|
|
{
|
|
name: "template builtin functions name",
|
|
funcName: "name",
|
|
funcArgs: []string{`"foo"`},
|
|
escape: true,
|
|
expected: "foo",
|
|
},
|
|
{
|
|
name: "template builtin functions name",
|
|
funcName: "name",
|
|
funcArgs: []string{`"foo_bar"`},
|
|
escape: true,
|
|
expected: "foo\\_bar",
|
|
},
|
|
{
|
|
name: "template builtin functions name",
|
|
funcName: "name",
|
|
funcArgs: []string{`"foo_bar"`},
|
|
escape: false,
|
|
expected: "foo_bar",
|
|
},
|
|
{
|
|
name: "template builtin functions name",
|
|
funcName: "name",
|
|
funcArgs: []string{`""`},
|
|
escape: true,
|
|
expected: "",
|
|
},
|
|
|
|
// sanitizeSection
|
|
{
|
|
name: "template builtin functions sanitizeSection",
|
|
funcName: "sanitizeSection",
|
|
funcArgs: []string{"\"Example of 'foo_bar' module in `foo_bar.tf`.\n\n| Foo | Bar |\n|-----|-----|\n| foo | bar |\""},
|
|
escape: true,
|
|
expected: "Example of 'foo\\_bar' module in `foo_bar.tf`.\n\n| Foo | Bar |\n|-----|-----|\n| foo | bar |",
|
|
},
|
|
{
|
|
name: "template builtin functions sanitizeSection",
|
|
funcName: "sanitizeSection",
|
|
funcArgs: []string{"\"Example of 'foo_bar' module in `foo_bar.tf`.\n\n| Foo | Bar |\""},
|
|
escape: false,
|
|
expected: "Example of 'foo_bar' module in `foo_bar.tf`.\n\n| Foo | Bar |",
|
|
},
|
|
{
|
|
name: "template builtin functions sanitizeSection",
|
|
funcName: "sanitizeSection",
|
|
funcArgs: []string{`""`},
|
|
escape: true,
|
|
expected: "n/a",
|
|
},
|
|
|
|
// sanitizeDoc
|
|
{
|
|
name: "template builtin functions sanitizeDoc",
|
|
funcName: "sanitizeDoc",
|
|
funcArgs: []string{"\"Example of 'foo_bar' module in `foo_bar.tf`.\n\n| Foo | Bar |\""},
|
|
escape: true,
|
|
expected: "Example of 'foo\\_bar' module in `foo_bar.tf`.\n\n| Foo | Bar |",
|
|
},
|
|
{
|
|
name: "template builtin functions sanitizeDoc",
|
|
funcName: "sanitizeDoc",
|
|
funcArgs: []string{"\"Example of 'foo_bar' module in `foo_bar.tf`.\n\n| Foo | Bar |\""},
|
|
escape: false,
|
|
expected: "Example of 'foo_bar' module in `foo_bar.tf`.\n\n| Foo | Bar |",
|
|
},
|
|
{
|
|
name: "template builtin functions sanitizeDoc",
|
|
funcName: "sanitizeDoc",
|
|
funcArgs: []string{`""`},
|
|
escape: true,
|
|
expected: "n/a",
|
|
},
|
|
|
|
// sanitizeMarkdownTbl
|
|
{
|
|
name: "template builtin functions sanitizeMarkdownTbl",
|
|
funcName: "sanitizeMarkdownTbl",
|
|
funcArgs: []string{"\"Example of 'foo_bar' module in `foo_bar.tf`.\n\n| Foo | Bar |\""},
|
|
escape: true,
|
|
expected: "Example of 'foo\\_bar' module in `foo_bar.tf`.<br/><br/>\\| Foo \\| Bar \\|",
|
|
},
|
|
{
|
|
name: "template builtin functions sanitizeMarkdownTbl",
|
|
funcName: "sanitizeMarkdownTbl",
|
|
funcArgs: []string{"\"Example of 'foo_bar' module in `foo_bar.tf`.\n\n| Foo | Bar |\""},
|
|
escape: false,
|
|
expected: "Example of 'foo_bar' module in `foo_bar.tf`.<br/><br/>\\| Foo \\| Bar \\|",
|
|
},
|
|
{
|
|
name: "template builtin functions sanitizeMarkdownTbl",
|
|
funcName: "sanitizeMarkdownTbl",
|
|
funcArgs: []string{`""`},
|
|
escape: true,
|
|
expected: "n/a",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert := assert.New(t)
|
|
config := print.DefaultConfig()
|
|
config.Settings.Escape = tt.escape
|
|
funcs := builtinFuncs(config)
|
|
|
|
fn, ok := funcs[tt.funcName]
|
|
assert.Truef(ok, "function %s is not defined", tt.funcName)
|
|
|
|
v := reflect.ValueOf(fn)
|
|
tp := v.Type()
|
|
assert.Equalf(len(tt.funcArgs), tp.NumIn(), "invalid number of arguments. got: %v, want: %v", len(tt.funcArgs), tp.NumIn())
|
|
|
|
argv := make([]reflect.Value, len(tt.funcArgs))
|
|
|
|
for i := range argv {
|
|
var argType reflect.Kind
|
|
if strings.HasPrefix(tt.funcArgs[i], "\"") {
|
|
if tt.funcName == "tostring" {
|
|
argType = reflect.TypeOf(types.String("")).Kind()
|
|
argv[i] = reflect.ValueOf(types.String(strings.Trim(tt.funcArgs[i], "\"")))
|
|
} else {
|
|
argType = reflect.String
|
|
argv[i] = reflect.ValueOf(strings.Trim(tt.funcArgs[i], "\""))
|
|
}
|
|
} else {
|
|
argType = reflect.Int
|
|
num, _ := strconv.Atoi(tt.funcArgs[i])
|
|
argv[i] = reflect.ValueOf(num)
|
|
}
|
|
if tp.In(i).Kind() != argType {
|
|
assert.Fail("Invalid argument. got: %v, want: %v", argType, tp.In(i).Kind())
|
|
}
|
|
}
|
|
|
|
result := v.Call(argv)
|
|
|
|
if len(result) != 1 || result[0].Kind() != reflect.String {
|
|
assert.Fail("function %s must return a one string value", tt.funcName)
|
|
}
|
|
|
|
assert.Equal(tt.expected, result[0].String())
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGenerateIndentation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
base int
|
|
extra int
|
|
expected string
|
|
}{
|
|
{
|
|
name: "generate indentation",
|
|
base: 2,
|
|
extra: 1,
|
|
expected: "###",
|
|
},
|
|
{
|
|
name: "generate indentation",
|
|
extra: 2,
|
|
expected: "####",
|
|
},
|
|
{
|
|
name: "generate indentation",
|
|
base: 4,
|
|
extra: 3,
|
|
expected: "#######",
|
|
},
|
|
{
|
|
name: "generate indentation",
|
|
base: 0,
|
|
extra: 0,
|
|
expected: "##",
|
|
},
|
|
{
|
|
name: "generate indentation",
|
|
base: 6,
|
|
extra: 1,
|
|
expected: "###",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert := assert.New(t)
|
|
actual := GenerateIndentation(tt.base, tt.extra, "#")
|
|
|
|
assert.Equal(tt.expected, actual)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNormalize(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
text string
|
|
trim bool
|
|
expected string
|
|
}{
|
|
{
|
|
name: "normalize with trim space",
|
|
text: "Lorem ipsum\ndolor sit amet,\nconsectetur\nadipiscing\nelit",
|
|
trim: true,
|
|
expected: "Lorem ipsum\ndolor sit amet,\nconsectetur\nadipiscing\nelit",
|
|
},
|
|
{
|
|
name: "normalize with trim space",
|
|
text: "Lorem ipsum\ndolor sit amet,\nconsectetur\nadipiscing\nelit\n",
|
|
trim: true,
|
|
expected: "Lorem ipsum\ndolor sit amet,\nconsectetur\nadipiscing\nelit\n",
|
|
},
|
|
{
|
|
name: "normalize with trim space",
|
|
text: "Lorem ipsum\ndolor sit amet,\n consectetur\nadipiscing\nelit",
|
|
trim: true,
|
|
expected: "Lorem ipsum\ndolor sit amet,\nconsectetur\nadipiscing\nelit",
|
|
},
|
|
{
|
|
name: "normalize without trim space",
|
|
text: "Lorem ipsum\ndolor sit amet,\nconsectetur\nadipiscing\nelit",
|
|
trim: false,
|
|
expected: "Lorem ipsum\ndolor sit amet,\nconsectetur\nadipiscing\nelit",
|
|
},
|
|
{
|
|
name: "normalize without trim space",
|
|
text: "Lorem ipsum\ndolor sit amet,\n consectetur\nadipiscing\nelit",
|
|
trim: false,
|
|
expected: "Lorem ipsum\ndolor sit amet,\n consectetur\nadipiscing\nelit",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert := assert.New(t)
|
|
actual := normalize(tt.text, tt.trim)
|
|
|
|
assert.Equal(tt.expected, actual)
|
|
})
|
|
}
|
|
}
|