mirror of
https://github.com/go-task/task.git
synced 2026-08-29 10:08:27 +02:00
test(templater): snapshot the template function surface and behaviour
Golden tests capturing the sorted list of template function names and the rendered output of a representative expression per function. Generated against the current slim-sprig implementation so that any change of templating library produces an auditable diff.
This commit is contained in:
325
internal/templater/snapshot_test.go
Normal file
325
internal/templater/snapshot_test.go
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
package templater
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"maps"
|
||||||
|
"os"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/sebdah/goldie/v2"
|
||||||
|
|
||||||
|
"github.com/go-task/task/v3/taskfile/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The two tests in this file snapshot the entire template surface: the set of
|
||||||
|
// function names, and the rendered output of a representative expression per
|
||||||
|
// function. They exist to make any change of templating library auditable —
|
||||||
|
// the golden diff is the exhaustive list of what changed for users.
|
||||||
|
//
|
||||||
|
// Expressions must stay deterministic and platform independent, so anything
|
||||||
|
// depending on the clock, the filesystem, the environment or randomness is
|
||||||
|
// deliberately absent (`now`, `uuid`, `randInt`, `env`, `os*`, `exeExt`, `OS`,
|
||||||
|
// `ARCH`, `spew`, `getHostByName`). Those are covered by unit tests instead.
|
||||||
|
|
||||||
|
// TestMain pins the local timezone so that the date expressions below render
|
||||||
|
// identically on every machine. A consequence is that this golden cannot show
|
||||||
|
// the local-vs-UTC difference between sprig's `date`/`toDate` and sprout's —
|
||||||
|
// that one belongs in the migration documentation.
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
time.Local = time.UTC
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFuncNames(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
names := slices.Sorted(maps.Keys(templateFuncs))
|
||||||
|
|
||||||
|
g := goldie.New(t)
|
||||||
|
g.Assert(t, "func_names", []byte(strings.Join(names, "\n")+"\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFuncBehaviour(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var b strings.Builder
|
||||||
|
for _, group := range funcBehaviourGroups {
|
||||||
|
fmt.Fprintf(&b, "## %s\n\n", group.name)
|
||||||
|
for _, expr := range group.exprs {
|
||||||
|
cache := &Cache{Vars: ast.NewVars()}
|
||||||
|
got := ReplaceWithExtra(expr, cache, nil)
|
||||||
|
fmt.Fprintf(&b, "%s\n", expr)
|
||||||
|
if err := cache.Err(); err != nil {
|
||||||
|
fmt.Fprintf(&b, "\t! %s\n", normalizeTemplateError(err))
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(&b, "\t= %s\n", strings.ReplaceAll(got, "\n", "\\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
g := goldie.New(t)
|
||||||
|
g.Assert(t, "func_behaviour", []byte(b.String()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizeTemplateError strips the position prefix that text/template adds to
|
||||||
|
// execution errors, which is noise in the golden and shifts whenever an
|
||||||
|
// expression is added to a group.
|
||||||
|
func normalizeTemplateError(err error) string {
|
||||||
|
s := err.Error()
|
||||||
|
if _, after, found := strings.Cut(s, `at <`); found {
|
||||||
|
return "at <" + after
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
var funcBehaviourGroups = []struct {
|
||||||
|
name string
|
||||||
|
exprs []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
// The ten functions whose argument order differs between sprig and
|
||||||
|
// sprout. Written here in sprig order, which is what users' Taskfiles
|
||||||
|
// contain today.
|
||||||
|
"argument order — sprig order (target first)",
|
||||||
|
[]string{
|
||||||
|
`{{ get (dict "a" "b") "a" }}`,
|
||||||
|
`{{ set (dict "a" "b") "c" "d" | toJson }}`,
|
||||||
|
`{{ unset (dict "a" "b" "c" "d") "a" | toJson }}`,
|
||||||
|
`{{ hasKey (dict "a" "b") "a" }}`,
|
||||||
|
`{{ pick (dict "a" "1" "b" "2") "a" | toJson }}`,
|
||||||
|
`{{ omit (dict "a" "1" "b" "2") "a" | toJson }}`,
|
||||||
|
`{{ append (list 1 2) 3 | toJson }}`,
|
||||||
|
`{{ push (list 1 2) 3 | toJson }}`,
|
||||||
|
`{{ prepend (list 2 3) 1 | toJson }}`,
|
||||||
|
`{{ without (list 1 2 3) 2 | toJson }}`,
|
||||||
|
`{{ slice (list 1 2 3 4) 1 3 | toJson }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Same ten functions in sprout order. Today these mostly fail; after
|
||||||
|
// the migration both forms must work.
|
||||||
|
"argument order — sprout order (target last)",
|
||||||
|
[]string{
|
||||||
|
`{{ dict "a" "b" | get "a" }}`,
|
||||||
|
`{{ dict "a" "b" | set "c" "d" | toJson }}`,
|
||||||
|
`{{ dict "a" "b" "c" "d" | unset "a" | toJson }}`,
|
||||||
|
`{{ dict "a" "b" | hasKey "a" }}`,
|
||||||
|
`{{ list 1 2 | append 3 | toJson }}`,
|
||||||
|
`{{ list 2 3 | prepend 1 | toJson }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"maps — unchanged signatures",
|
||||||
|
[]string{
|
||||||
|
`{{ dict "a" 1 "b" 2 | toJson }}`,
|
||||||
|
`{{ keys (dict "b" 1 "a" 2) | sortAlpha | toJson }}`,
|
||||||
|
`{{ values (dict "a" 1) | toJson }}`,
|
||||||
|
`{{ pluck "a" (dict "a" 1) (dict "a" 2) | toJson }}`,
|
||||||
|
`{{ dig "a" "b" "fallback" (dict "a" (dict "b" "found")) }}`,
|
||||||
|
`{{ dig "a" "missing" "fallback" (dict "a" (dict "b" "found")) }}`,
|
||||||
|
`{{ dig "a.b" "fallback" (dict "a" (dict "b" "found")) }}`,
|
||||||
|
`{{ merge (dict "a" 1) (dict "b" 2) | toJson }}`,
|
||||||
|
`{{ merge (dict "a" 1) (dict "a" 0) | toJson }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lists",
|
||||||
|
[]string{
|
||||||
|
`{{ list 1 2 3 | toJson }}`,
|
||||||
|
`{{ tuple 1 2 3 | toJson }}`,
|
||||||
|
`{{ first (list 1 2 3) }}`,
|
||||||
|
`{{ last (list 1 2 3) }}`,
|
||||||
|
`{{ rest (list 1 2 3) | toJson }}`,
|
||||||
|
`{{ initial (list 1 2 3) | toJson }}`,
|
||||||
|
`{{ reverse (list 1 2 3) | toJson }}`,
|
||||||
|
`{{ uniq (list 1 1 2) | toJson }}`,
|
||||||
|
`{{ compact (list 1 "" 2) | toJson }}`,
|
||||||
|
`{{ concat (list 1) (list 2) | toJson }}`,
|
||||||
|
`{{ chunk 2 (list 1 2 3) | toJson }}`,
|
||||||
|
`{{ has 2 (list 1 2 3) }}`,
|
||||||
|
`{{ sortAlpha (list "b" "a") | toJson }}`,
|
||||||
|
`{{ splitList "," "a,b,c" | toJson }}`,
|
||||||
|
`{{ toStrings (list 1 2) | toJson }}`,
|
||||||
|
`{{ until 3 | toJson }}`,
|
||||||
|
`{{ untilStep 0 6 2 | toJson }}`,
|
||||||
|
`{{ seq 1 3 }}`,
|
||||||
|
`{{ join "," (list "a" "b") }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"strings",
|
||||||
|
[]string{
|
||||||
|
`{{ trim " x " }}`,
|
||||||
|
`{{ trimAll "-" "-x-" }}`,
|
||||||
|
`{{ trimall "-" "-x-" }}`,
|
||||||
|
`{{ trimPrefix "a" "ab" }}`,
|
||||||
|
`{{ trimSuffix "b" "ab" }}`,
|
||||||
|
`{{ upper "abc" }}`,
|
||||||
|
`{{ lower "ABC" }}`,
|
||||||
|
`{{ title "hello world" }}`,
|
||||||
|
`{{ title "hello wORLD" }}`,
|
||||||
|
`{{ trunc 3 "foobar" }}`,
|
||||||
|
`{{ trunc -3 "foobar" }}`,
|
||||||
|
`{{ substr 0 3 "foobar" }}`,
|
||||||
|
`{{ substr 0 -3 "foobar" }}`,
|
||||||
|
`{{ repeat 3 "x" }}`,
|
||||||
|
`{{ contains "oo" "foobar" }}`,
|
||||||
|
`{{ hasPrefix "foo" "foobar" }}`,
|
||||||
|
`{{ hasSuffix "bar" "foobar" }}`,
|
||||||
|
`{{ quote "x" }}`,
|
||||||
|
`{{ squote "x" }}`,
|
||||||
|
`{{ cat "a" "b" }}`,
|
||||||
|
`{{ indent 2 "x" }}`,
|
||||||
|
`{{ nindent 2 "x" }}`,
|
||||||
|
`{{ replace "a" "b" "aa" }}`,
|
||||||
|
`{{ plural "one" "many" 2 }}`,
|
||||||
|
`{{ split "," "a,b" | toJson }}`,
|
||||||
|
`{{ splitn "," 2 "a,b,c" | toJson }}`,
|
||||||
|
`{{ toString 42 }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"numbers",
|
||||||
|
[]string{
|
||||||
|
`{{ add 1 2 }}`,
|
||||||
|
`{{ add1 1 }}`,
|
||||||
|
`{{ sub 5 2 }}`,
|
||||||
|
`{{ mul 2 3 }}`,
|
||||||
|
`{{ div 6 2 }}`,
|
||||||
|
`{{ mod 5 3 }}`,
|
||||||
|
`{{ max 1 5 3 }}`,
|
||||||
|
`{{ min 1 5 3 }}`,
|
||||||
|
`{{ biggest 1 5 3 }}`,
|
||||||
|
`{{ maxf 1.5 2.5 }}`,
|
||||||
|
`{{ minf 1.5 2.5 }}`,
|
||||||
|
`{{ ceil 1.1 }}`,
|
||||||
|
`{{ floor 1.9 }}`,
|
||||||
|
`{{ round 1.55 1 }}`,
|
||||||
|
`{{ atoi "42" }}`,
|
||||||
|
`{{ atoi "abc" }}`,
|
||||||
|
`{{ int "42" }}`,
|
||||||
|
`{{ int64 "42" }}`,
|
||||||
|
`{{ float64 "1.5" }}`,
|
||||||
|
`{{ toDecimal "0777" }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"defaults and flow",
|
||||||
|
[]string{
|
||||||
|
`{{ default "d" "" }}`,
|
||||||
|
`{{ default "d" "x" }}`,
|
||||||
|
`{{ empty "" }}`,
|
||||||
|
`{{ empty 0 }}`,
|
||||||
|
`{{ coalesce "" "x" }}`,
|
||||||
|
`{{ all 1 1 }}`,
|
||||||
|
`{{ any 0 1 }}`,
|
||||||
|
`{{ ternary "y" "n" true }}`,
|
||||||
|
`{{ fail "boom" }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"encoding",
|
||||||
|
[]string{
|
||||||
|
`{{ toJson (dict "a" 1) }}`,
|
||||||
|
`{{ toPrettyJson (dict "a" 1) }}`,
|
||||||
|
`{{ toRawJson (dict "a" "<b>") }}`,
|
||||||
|
`{{ fromJson "{\"a\":1}" | toJson }}`,
|
||||||
|
`{{ fromJson "not json" | toJson }}`,
|
||||||
|
`{{ mustFromJson "not json" | toJson }}`,
|
||||||
|
`{{ toYaml (dict "a" 1) }}`,
|
||||||
|
`{{ fromYaml "a: 1" | toJson }}`,
|
||||||
|
`{{ mustFromYaml "a: :" | toJson }}`,
|
||||||
|
`{{ b64enc "hello" }}`,
|
||||||
|
`{{ b64dec "aGVsbG8=" }}`,
|
||||||
|
`{{ b32enc "hello" }}`,
|
||||||
|
`{{ b32dec "NBSWY3DP" }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"regex",
|
||||||
|
[]string{
|
||||||
|
`{{ regexMatch "^a" "abc" }}`,
|
||||||
|
`{{ regexFind "[0-9]+" "abc123" }}`,
|
||||||
|
`{{ regexFindAll "[0-9]" "a1b2" -1 | toJson }}`,
|
||||||
|
`{{ regexReplaceAll "[0-9]" "abc123" "#" }}`,
|
||||||
|
`{{ regexReplaceAllLiteral "[0-9]" "abc123" "#" }}`,
|
||||||
|
`{{ regexSplit "," "a,b" -1 | toJson }}`,
|
||||||
|
`{{ regexQuoteMeta "a.b" }}`,
|
||||||
|
`{{ mustRegexFind "[" "abc" }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reflection",
|
||||||
|
[]string{
|
||||||
|
`{{ typeOf 1 }}`,
|
||||||
|
`{{ typeIs "int" 1 }}`,
|
||||||
|
`{{ typeIsLike "int" 1 }}`,
|
||||||
|
`{{ kindOf 1 }}`,
|
||||||
|
`{{ kindOf (list 1) }}`,
|
||||||
|
`{{ kindIs "int" 1 }}`,
|
||||||
|
`{{ deepEqual (list 1) (list 1) }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"checksums",
|
||||||
|
[]string{
|
||||||
|
`{{ sha1sum "x" }}`,
|
||||||
|
`{{ sha256sum "x" }}`,
|
||||||
|
`{{ adler32sum "x" }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// path.* semantics — slash based, therefore identical on every platform.
|
||||||
|
"paths",
|
||||||
|
[]string{
|
||||||
|
`{{ base "/foo/bar.txt" }}`,
|
||||||
|
`{{ dir "/foo/bar.txt" }}`,
|
||||||
|
`{{ ext "/foo/bar.txt" }}`,
|
||||||
|
`{{ clean "/foo//bar" }}`,
|
||||||
|
`{{ isAbs "/foo" }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"dates — fixed epoch, explicit zone",
|
||||||
|
[]string{
|
||||||
|
`{{ dateInZone "2006-01-02T15:04:05" 0 "UTC" }}`,
|
||||||
|
`{{ date "2006-01-02T15:04:05" 0 }}`,
|
||||||
|
`{{ dateModify "1h" (toDate "2006-01-02T15:04:05Z07:00" "2020-01-01T00:00:00Z") }}`,
|
||||||
|
`{{ date_modify "1h" (toDate "2006-01-02T15:04:05Z07:00" "2020-01-01T00:00:00Z") }}`,
|
||||||
|
`{{ toDate "2006-01-02" "2020-01-01" }}`,
|
||||||
|
`{{ unixEpoch (toDate "2006-01-02" "2020-01-01") }}`,
|
||||||
|
`{{ duration 90 }}`,
|
||||||
|
`{{ durationRound "1h35m30s" }}`,
|
||||||
|
`{{ htmlDate 0 }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"urls",
|
||||||
|
[]string{
|
||||||
|
`{{ urlParse "http://example.com/a?b=c" | toJson }}`,
|
||||||
|
`{{ urlJoin (dict "scheme" "http" "host" "example.com" "path" "/a") }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"task's own functions",
|
||||||
|
[]string{
|
||||||
|
`{{ numCPU | kindOf }}`,
|
||||||
|
`{{ catLines "a\nb" }}`,
|
||||||
|
`{{ splitLines "a\nb" | toJson }}`,
|
||||||
|
`{{ toSlash "a/b" }}`,
|
||||||
|
`{{ fromSlash "a/b" | kindOf }}`,
|
||||||
|
`{{ ToSlash "a/b" }}`,
|
||||||
|
`{{ shellQuote "a b" }}`,
|
||||||
|
`{{ q "a b" }}`,
|
||||||
|
`{{ splitArgs "a b c" | toJson }}`,
|
||||||
|
`{{ IsSH }}`,
|
||||||
|
`{{ joinUrl "http://localhost" "a" "b" }}`,
|
||||||
|
`{{ mustToYaml (dict "a" 1) }}`,
|
||||||
|
`{{ randIntN 1 }}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
367
internal/templater/testdata/func_behaviour.golden
vendored
Normal file
367
internal/templater/testdata/func_behaviour.golden
vendored
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
## argument order — sprig order (target first)
|
||||||
|
|
||||||
|
{{ get (dict "a" "b") "a" }}
|
||||||
|
= b
|
||||||
|
{{ set (dict "a" "b") "c" "d" | toJson }}
|
||||||
|
= {"a":"b","c":"d"}
|
||||||
|
{{ unset (dict "a" "b" "c" "d") "a" | toJson }}
|
||||||
|
= {"c":"d"}
|
||||||
|
{{ hasKey (dict "a" "b") "a" }}
|
||||||
|
= true
|
||||||
|
{{ pick (dict "a" "1" "b" "2") "a" | toJson }}
|
||||||
|
= {"a":"1"}
|
||||||
|
{{ omit (dict "a" "1" "b" "2") "a" | toJson }}
|
||||||
|
= {"b":"2"}
|
||||||
|
{{ append (list 1 2) 3 | toJson }}
|
||||||
|
= [1,2,3]
|
||||||
|
{{ push (list 1 2) 3 | toJson }}
|
||||||
|
= [1,2,3]
|
||||||
|
{{ prepend (list 2 3) 1 | toJson }}
|
||||||
|
= [1,2,3]
|
||||||
|
{{ without (list 1 2 3) 2 | toJson }}
|
||||||
|
= [1,3]
|
||||||
|
{{ slice (list 1 2 3 4) 1 3 | toJson }}
|
||||||
|
= [2,3]
|
||||||
|
|
||||||
|
## argument order — sprout order (target last)
|
||||||
|
|
||||||
|
{{ dict "a" "b" | get "a" }}
|
||||||
|
! at <"a">: can't handle "a" for arg of type map[string]interface {}
|
||||||
|
{{ dict "a" "b" | set "c" "d" | toJson }}
|
||||||
|
! at <"c">: can't handle "c" for arg of type map[string]interface {}
|
||||||
|
{{ dict "a" "b" "c" "d" | unset "a" | toJson }}
|
||||||
|
! at <"a">: can't handle "a" for arg of type map[string]interface {}
|
||||||
|
{{ dict "a" "b" | hasKey "a" }}
|
||||||
|
! at <"a">: can't handle "a" for arg of type map[string]interface {}
|
||||||
|
{{ list 1 2 | append 3 | toJson }}
|
||||||
|
! at <append 3>: error calling append: Cannot push on type int
|
||||||
|
{{ list 2 3 | prepend 1 | toJson }}
|
||||||
|
! at <prepend 1>: error calling prepend: Cannot prepend on type int
|
||||||
|
|
||||||
|
## maps — unchanged signatures
|
||||||
|
|
||||||
|
{{ dict "a" 1 "b" 2 | toJson }}
|
||||||
|
= {"a":1,"b":2}
|
||||||
|
{{ keys (dict "b" 1 "a" 2) | sortAlpha | toJson }}
|
||||||
|
= ["a","b"]
|
||||||
|
{{ values (dict "a" 1) | toJson }}
|
||||||
|
= [1]
|
||||||
|
{{ pluck "a" (dict "a" 1) (dict "a" 2) | toJson }}
|
||||||
|
= [1,2]
|
||||||
|
{{ dig "a" "b" "fallback" (dict "a" (dict "b" "found")) }}
|
||||||
|
= found
|
||||||
|
{{ dig "a" "missing" "fallback" (dict "a" (dict "b" "found")) }}
|
||||||
|
= fallback
|
||||||
|
{{ dig "a.b" "fallback" (dict "a" (dict "b" "found")) }}
|
||||||
|
= fallback
|
||||||
|
{{ merge (dict "a" 1) (dict "b" 2) | toJson }}
|
||||||
|
= {"a":1,"b":2}
|
||||||
|
{{ merge (dict "a" 1) (dict "a" 0) | toJson }}
|
||||||
|
= {"a":0}
|
||||||
|
|
||||||
|
## lists
|
||||||
|
|
||||||
|
{{ list 1 2 3 | toJson }}
|
||||||
|
= [1,2,3]
|
||||||
|
{{ tuple 1 2 3 | toJson }}
|
||||||
|
= [1,2,3]
|
||||||
|
{{ first (list 1 2 3) }}
|
||||||
|
= 1
|
||||||
|
{{ last (list 1 2 3) }}
|
||||||
|
= 3
|
||||||
|
{{ rest (list 1 2 3) | toJson }}
|
||||||
|
= [2,3]
|
||||||
|
{{ initial (list 1 2 3) | toJson }}
|
||||||
|
= [1,2]
|
||||||
|
{{ reverse (list 1 2 3) | toJson }}
|
||||||
|
= [3,2,1]
|
||||||
|
{{ uniq (list 1 1 2) | toJson }}
|
||||||
|
= [1,2]
|
||||||
|
{{ compact (list 1 "" 2) | toJson }}
|
||||||
|
= [1,2]
|
||||||
|
{{ concat (list 1) (list 2) | toJson }}
|
||||||
|
= [1,2]
|
||||||
|
{{ chunk 2 (list 1 2 3) | toJson }}
|
||||||
|
= [[1,2],[3]]
|
||||||
|
{{ has 2 (list 1 2 3) }}
|
||||||
|
= true
|
||||||
|
{{ sortAlpha (list "b" "a") | toJson }}
|
||||||
|
= ["a","b"]
|
||||||
|
{{ splitList "," "a,b,c" | toJson }}
|
||||||
|
= ["a","b","c"]
|
||||||
|
{{ toStrings (list 1 2) | toJson }}
|
||||||
|
= ["1","2"]
|
||||||
|
{{ until 3 | toJson }}
|
||||||
|
= [0,1,2]
|
||||||
|
{{ untilStep 0 6 2 | toJson }}
|
||||||
|
= [0,2,4]
|
||||||
|
{{ seq 1 3 }}
|
||||||
|
= 1 2 3
|
||||||
|
{{ join "," (list "a" "b") }}
|
||||||
|
= a,b
|
||||||
|
|
||||||
|
## strings
|
||||||
|
|
||||||
|
{{ trim " x " }}
|
||||||
|
= x
|
||||||
|
{{ trimAll "-" "-x-" }}
|
||||||
|
= x
|
||||||
|
{{ trimall "-" "-x-" }}
|
||||||
|
= x
|
||||||
|
{{ trimPrefix "a" "ab" }}
|
||||||
|
= b
|
||||||
|
{{ trimSuffix "b" "ab" }}
|
||||||
|
= a
|
||||||
|
{{ upper "abc" }}
|
||||||
|
= ABC
|
||||||
|
{{ lower "ABC" }}
|
||||||
|
= abc
|
||||||
|
{{ title "hello world" }}
|
||||||
|
= Hello World
|
||||||
|
{{ title "hello wORLD" }}
|
||||||
|
= Hello WORLD
|
||||||
|
{{ trunc 3 "foobar" }}
|
||||||
|
= foo
|
||||||
|
{{ trunc -3 "foobar" }}
|
||||||
|
= bar
|
||||||
|
{{ substr 0 3 "foobar" }}
|
||||||
|
= foo
|
||||||
|
{{ substr 0 -3 "foobar" }}
|
||||||
|
= foobar
|
||||||
|
{{ repeat 3 "x" }}
|
||||||
|
= xxx
|
||||||
|
{{ contains "oo" "foobar" }}
|
||||||
|
= true
|
||||||
|
{{ hasPrefix "foo" "foobar" }}
|
||||||
|
= true
|
||||||
|
{{ hasSuffix "bar" "foobar" }}
|
||||||
|
= true
|
||||||
|
{{ quote "x" }}
|
||||||
|
= "x"
|
||||||
|
{{ squote "x" }}
|
||||||
|
= 'x'
|
||||||
|
{{ cat "a" "b" }}
|
||||||
|
= a b
|
||||||
|
{{ indent 2 "x" }}
|
||||||
|
= x
|
||||||
|
{{ nindent 2 "x" }}
|
||||||
|
= \n x
|
||||||
|
{{ replace "a" "b" "aa" }}
|
||||||
|
= bb
|
||||||
|
{{ plural "one" "many" 2 }}
|
||||||
|
= many
|
||||||
|
{{ split "," "a,b" | toJson }}
|
||||||
|
= {"_0":"a","_1":"b"}
|
||||||
|
{{ splitn "," 2 "a,b,c" | toJson }}
|
||||||
|
= {"_0":"a","_1":"b,c"}
|
||||||
|
{{ toString 42 }}
|
||||||
|
= 42
|
||||||
|
|
||||||
|
## numbers
|
||||||
|
|
||||||
|
{{ add 1 2 }}
|
||||||
|
= 3
|
||||||
|
{{ add1 1 }}
|
||||||
|
= 2
|
||||||
|
{{ sub 5 2 }}
|
||||||
|
= 3
|
||||||
|
{{ mul 2 3 }}
|
||||||
|
= 6
|
||||||
|
{{ div 6 2 }}
|
||||||
|
= 3
|
||||||
|
{{ mod 5 3 }}
|
||||||
|
= 2
|
||||||
|
{{ max 1 5 3 }}
|
||||||
|
= 5
|
||||||
|
{{ min 1 5 3 }}
|
||||||
|
= 1
|
||||||
|
{{ biggest 1 5 3 }}
|
||||||
|
= 5
|
||||||
|
{{ maxf 1.5 2.5 }}
|
||||||
|
= 2.5
|
||||||
|
{{ minf 1.5 2.5 }}
|
||||||
|
= 1.5
|
||||||
|
{{ ceil 1.1 }}
|
||||||
|
= 2
|
||||||
|
{{ floor 1.9 }}
|
||||||
|
= 1
|
||||||
|
{{ round 1.55 1 }}
|
||||||
|
= 1.6
|
||||||
|
{{ atoi "42" }}
|
||||||
|
= 42
|
||||||
|
{{ atoi "abc" }}
|
||||||
|
= 0
|
||||||
|
{{ int "42" }}
|
||||||
|
= 42
|
||||||
|
{{ int64 "42" }}
|
||||||
|
= 42
|
||||||
|
{{ float64 "1.5" }}
|
||||||
|
= 1.5
|
||||||
|
{{ toDecimal "0777" }}
|
||||||
|
= 511
|
||||||
|
|
||||||
|
## defaults and flow
|
||||||
|
|
||||||
|
{{ default "d" "" }}
|
||||||
|
= d
|
||||||
|
{{ default "d" "x" }}
|
||||||
|
= x
|
||||||
|
{{ empty "" }}
|
||||||
|
= true
|
||||||
|
{{ empty 0 }}
|
||||||
|
= true
|
||||||
|
{{ coalesce "" "x" }}
|
||||||
|
= x
|
||||||
|
{{ all 1 1 }}
|
||||||
|
= true
|
||||||
|
{{ any 0 1 }}
|
||||||
|
= true
|
||||||
|
{{ ternary "y" "n" true }}
|
||||||
|
= y
|
||||||
|
{{ fail "boom" }}
|
||||||
|
! at <fail "boom">: error calling fail: boom
|
||||||
|
|
||||||
|
## encoding
|
||||||
|
|
||||||
|
{{ toJson (dict "a" 1) }}
|
||||||
|
= {"a":1}
|
||||||
|
{{ toPrettyJson (dict "a" 1) }}
|
||||||
|
= {\n "a": 1\n}
|
||||||
|
{{ toRawJson (dict "a" "<b>") }}
|
||||||
|
= {"a":"<b>"}
|
||||||
|
{{ fromJson "{\"a\":1}" | toJson }}
|
||||||
|
= {"a":1}
|
||||||
|
{{ fromJson "not json" | toJson }}
|
||||||
|
= null
|
||||||
|
{{ mustFromJson "not json" | toJson }}
|
||||||
|
! at <mustFromJson "not json">: error calling mustFromJson: invalid character 'o' in literal null (expecting 'u')
|
||||||
|
{{ toYaml (dict "a" 1) }}
|
||||||
|
= a: 1\n
|
||||||
|
{{ fromYaml "a: 1" | toJson }}
|
||||||
|
= {"a":1}
|
||||||
|
{{ mustFromYaml "a: :" | toJson }}
|
||||||
|
! at <mustFromYaml "a: :">: error calling mustFromYaml: yaml: mapping values are not allowed in this context
|
||||||
|
{{ b64enc "hello" }}
|
||||||
|
= aGVsbG8=
|
||||||
|
{{ b64dec "aGVsbG8=" }}
|
||||||
|
= hello
|
||||||
|
{{ b32enc "hello" }}
|
||||||
|
= NBSWY3DP
|
||||||
|
{{ b32dec "NBSWY3DP" }}
|
||||||
|
= hello
|
||||||
|
|
||||||
|
## regex
|
||||||
|
|
||||||
|
{{ regexMatch "^a" "abc" }}
|
||||||
|
= true
|
||||||
|
{{ regexFind "[0-9]+" "abc123" }}
|
||||||
|
= 123
|
||||||
|
{{ regexFindAll "[0-9]" "a1b2" -1 | toJson }}
|
||||||
|
= ["1","2"]
|
||||||
|
{{ regexReplaceAll "[0-9]" "abc123" "#" }}
|
||||||
|
= abc###
|
||||||
|
{{ regexReplaceAllLiteral "[0-9]" "abc123" "#" }}
|
||||||
|
= abc###
|
||||||
|
{{ regexSplit "," "a,b" -1 | toJson }}
|
||||||
|
= ["a","b"]
|
||||||
|
{{ regexQuoteMeta "a.b" }}
|
||||||
|
= a\.b
|
||||||
|
{{ mustRegexFind "[" "abc" }}
|
||||||
|
! at <mustRegexFind "[" "abc">: error calling mustRegexFind: error parsing regexp: missing closing ]: `[`
|
||||||
|
|
||||||
|
## reflection
|
||||||
|
|
||||||
|
{{ typeOf 1 }}
|
||||||
|
= int
|
||||||
|
{{ typeIs "int" 1 }}
|
||||||
|
= true
|
||||||
|
{{ typeIsLike "int" 1 }}
|
||||||
|
= true
|
||||||
|
{{ kindOf 1 }}
|
||||||
|
= int
|
||||||
|
{{ kindOf (list 1) }}
|
||||||
|
= slice
|
||||||
|
{{ kindIs "int" 1 }}
|
||||||
|
= true
|
||||||
|
{{ deepEqual (list 1) (list 1) }}
|
||||||
|
= true
|
||||||
|
|
||||||
|
## checksums
|
||||||
|
|
||||||
|
{{ sha1sum "x" }}
|
||||||
|
= 11f6ad8ec52a2984abaafd7c3b516503785c2072
|
||||||
|
{{ sha256sum "x" }}
|
||||||
|
= 2d711642b726b04401627ca9fbac32f5c8530fb1903cc4db02258717921a4881
|
||||||
|
{{ adler32sum "x" }}
|
||||||
|
= 7929977
|
||||||
|
|
||||||
|
## paths
|
||||||
|
|
||||||
|
{{ base "/foo/bar.txt" }}
|
||||||
|
= bar.txt
|
||||||
|
{{ dir "/foo/bar.txt" }}
|
||||||
|
= /foo
|
||||||
|
{{ ext "/foo/bar.txt" }}
|
||||||
|
= .txt
|
||||||
|
{{ clean "/foo//bar" }}
|
||||||
|
= /foo/bar
|
||||||
|
{{ isAbs "/foo" }}
|
||||||
|
= true
|
||||||
|
|
||||||
|
## dates — fixed epoch, explicit zone
|
||||||
|
|
||||||
|
{{ dateInZone "2006-01-02T15:04:05" 0 "UTC" }}
|
||||||
|
= 1970-01-01T00:00:00
|
||||||
|
{{ date "2006-01-02T15:04:05" 0 }}
|
||||||
|
= 1970-01-01T00:00:00
|
||||||
|
{{ dateModify "1h" (toDate "2006-01-02T15:04:05Z07:00" "2020-01-01T00:00:00Z") }}
|
||||||
|
= 2020-01-01 01:00:00 +0000 UTC
|
||||||
|
{{ date_modify "1h" (toDate "2006-01-02T15:04:05Z07:00" "2020-01-01T00:00:00Z") }}
|
||||||
|
= 2020-01-01 01:00:00 +0000 UTC
|
||||||
|
{{ toDate "2006-01-02" "2020-01-01" }}
|
||||||
|
= 2020-01-01 00:00:00 +0000 UTC
|
||||||
|
{{ unixEpoch (toDate "2006-01-02" "2020-01-01") }}
|
||||||
|
= 1577836800
|
||||||
|
{{ duration 90 }}
|
||||||
|
= 0s
|
||||||
|
{{ durationRound "1h35m30s" }}
|
||||||
|
= 1h
|
||||||
|
{{ htmlDate 0 }}
|
||||||
|
= 1970-01-01
|
||||||
|
|
||||||
|
## urls
|
||||||
|
|
||||||
|
{{ urlParse "http://example.com/a?b=c" | toJson }}
|
||||||
|
= {"fragment":"","host":"example.com","hostname":"example.com","opaque":"","path":"/a","query":"b=c","scheme":"http","userinfo":""}
|
||||||
|
{{ urlJoin (dict "scheme" "http" "host" "example.com" "path" "/a") }}
|
||||||
|
= http://example.com/a
|
||||||
|
|
||||||
|
## task's own functions
|
||||||
|
|
||||||
|
{{ numCPU | kindOf }}
|
||||||
|
= int
|
||||||
|
{{ catLines "a\nb" }}
|
||||||
|
= a b
|
||||||
|
{{ splitLines "a\nb" | toJson }}
|
||||||
|
= ["a","b"]
|
||||||
|
{{ toSlash "a/b" }}
|
||||||
|
= a/b
|
||||||
|
{{ fromSlash "a/b" | kindOf }}
|
||||||
|
= string
|
||||||
|
{{ ToSlash "a/b" }}
|
||||||
|
= a/b
|
||||||
|
{{ shellQuote "a b" }}
|
||||||
|
= 'a b'
|
||||||
|
{{ q "a b" }}
|
||||||
|
= 'a b'
|
||||||
|
{{ splitArgs "a b c" | toJson }}
|
||||||
|
= ["a","b","c"]
|
||||||
|
{{ IsSH }}
|
||||||
|
= true
|
||||||
|
{{ joinUrl "http://localhost" "a" "b" }}
|
||||||
|
= http://localhost/a/b
|
||||||
|
{{ mustToYaml (dict "a" 1) }}
|
||||||
|
= a: 1\n
|
||||||
|
{{ randIntN 1 }}
|
||||||
|
= 0
|
||||||
|
|
||||||
194
internal/templater/testdata/func_names.golden
vendored
Normal file
194
internal/templater/testdata/func_names.golden
vendored
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
ARCH
|
||||||
|
ExeExt
|
||||||
|
FromSlash
|
||||||
|
IsSH
|
||||||
|
OS
|
||||||
|
ToSlash
|
||||||
|
absPath
|
||||||
|
add
|
||||||
|
add1
|
||||||
|
adler32sum
|
||||||
|
ago
|
||||||
|
all
|
||||||
|
any
|
||||||
|
append
|
||||||
|
atoi
|
||||||
|
b32dec
|
||||||
|
b32enc
|
||||||
|
b64dec
|
||||||
|
b64enc
|
||||||
|
base
|
||||||
|
biggest
|
||||||
|
cat
|
||||||
|
catLines
|
||||||
|
ceil
|
||||||
|
chunk
|
||||||
|
clean
|
||||||
|
coalesce
|
||||||
|
compact
|
||||||
|
concat
|
||||||
|
contains
|
||||||
|
date
|
||||||
|
dateInZone
|
||||||
|
dateModify
|
||||||
|
date_in_zone
|
||||||
|
date_modify
|
||||||
|
deepEqual
|
||||||
|
default
|
||||||
|
dict
|
||||||
|
dig
|
||||||
|
dir
|
||||||
|
div
|
||||||
|
duration
|
||||||
|
durationRound
|
||||||
|
empty
|
||||||
|
env
|
||||||
|
exeExt
|
||||||
|
expandenv
|
||||||
|
ext
|
||||||
|
fail
|
||||||
|
first
|
||||||
|
float64
|
||||||
|
floor
|
||||||
|
fromJson
|
||||||
|
fromSlash
|
||||||
|
fromYaml
|
||||||
|
get
|
||||||
|
getHostByName
|
||||||
|
has
|
||||||
|
hasKey
|
||||||
|
hasPrefix
|
||||||
|
hasSuffix
|
||||||
|
hello
|
||||||
|
htmlDate
|
||||||
|
htmlDateInZone
|
||||||
|
indent
|
||||||
|
initial
|
||||||
|
int
|
||||||
|
int64
|
||||||
|
isAbs
|
||||||
|
join
|
||||||
|
joinEnv
|
||||||
|
joinPath
|
||||||
|
joinUrl
|
||||||
|
keys
|
||||||
|
kindIs
|
||||||
|
kindOf
|
||||||
|
last
|
||||||
|
list
|
||||||
|
lower
|
||||||
|
max
|
||||||
|
maxf
|
||||||
|
merge
|
||||||
|
min
|
||||||
|
minf
|
||||||
|
mod
|
||||||
|
mul
|
||||||
|
mustAppend
|
||||||
|
mustChunk
|
||||||
|
mustCompact
|
||||||
|
mustDateModify
|
||||||
|
mustFirst
|
||||||
|
mustFromJson
|
||||||
|
mustFromYaml
|
||||||
|
mustHas
|
||||||
|
mustInitial
|
||||||
|
mustLast
|
||||||
|
mustPrepend
|
||||||
|
mustPush
|
||||||
|
mustRegexFind
|
||||||
|
mustRegexFindAll
|
||||||
|
mustRegexMatch
|
||||||
|
mustRegexReplaceAll
|
||||||
|
mustRegexReplaceAllLiteral
|
||||||
|
mustRegexSplit
|
||||||
|
mustRest
|
||||||
|
mustReverse
|
||||||
|
mustSlice
|
||||||
|
mustToDate
|
||||||
|
mustToJson
|
||||||
|
mustToPrettyJson
|
||||||
|
mustToRawJson
|
||||||
|
mustToYaml
|
||||||
|
mustUniq
|
||||||
|
mustWithout
|
||||||
|
must_date_modify
|
||||||
|
nindent
|
||||||
|
now
|
||||||
|
numCPU
|
||||||
|
omit
|
||||||
|
osBase
|
||||||
|
osClean
|
||||||
|
osDir
|
||||||
|
osExt
|
||||||
|
osIsAbs
|
||||||
|
pick
|
||||||
|
pluck
|
||||||
|
plural
|
||||||
|
prepend
|
||||||
|
push
|
||||||
|
q
|
||||||
|
quote
|
||||||
|
randInt
|
||||||
|
randIntN
|
||||||
|
regexFind
|
||||||
|
regexFindAll
|
||||||
|
regexMatch
|
||||||
|
regexQuoteMeta
|
||||||
|
regexReplaceAll
|
||||||
|
regexReplaceAllLiteral
|
||||||
|
regexSplit
|
||||||
|
relPath
|
||||||
|
repeat
|
||||||
|
replace
|
||||||
|
rest
|
||||||
|
reverse
|
||||||
|
round
|
||||||
|
seq
|
||||||
|
set
|
||||||
|
sha1sum
|
||||||
|
sha256sum
|
||||||
|
shellQuote
|
||||||
|
slice
|
||||||
|
sortAlpha
|
||||||
|
spew
|
||||||
|
split
|
||||||
|
splitArgs
|
||||||
|
splitLines
|
||||||
|
splitList
|
||||||
|
splitn
|
||||||
|
squote
|
||||||
|
sub
|
||||||
|
substr
|
||||||
|
ternary
|
||||||
|
title
|
||||||
|
toDate
|
||||||
|
toDecimal
|
||||||
|
toJson
|
||||||
|
toPrettyJson
|
||||||
|
toRawJson
|
||||||
|
toSlash
|
||||||
|
toString
|
||||||
|
toStrings
|
||||||
|
toYaml
|
||||||
|
trim
|
||||||
|
trimAll
|
||||||
|
trimPrefix
|
||||||
|
trimSuffix
|
||||||
|
trimall
|
||||||
|
trunc
|
||||||
|
tuple
|
||||||
|
typeIs
|
||||||
|
typeIsLike
|
||||||
|
typeOf
|
||||||
|
uniq
|
||||||
|
unixEpoch
|
||||||
|
unset
|
||||||
|
until
|
||||||
|
untilStep
|
||||||
|
upper
|
||||||
|
urlJoin
|
||||||
|
urlParse
|
||||||
|
uuid
|
||||||
|
values
|
||||||
|
without
|
||||||
Reference in New Issue
Block a user