410 lines
10 KiB
Go
410 lines
10 KiB
Go
package hclparser
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
func TestIndexOf(t *testing.T) {
|
|
type testCase struct {
|
|
input cty.Value
|
|
key cty.Value
|
|
want cty.Value
|
|
wantErr bool
|
|
}
|
|
tests := map[string]testCase{
|
|
"index 0": {
|
|
input: cty.TupleVal([]cty.Value{cty.StringVal("one"), cty.NumberIntVal(2.0), cty.NumberIntVal(3), cty.StringVal("four")}),
|
|
key: cty.StringVal("one"),
|
|
want: cty.NumberIntVal(0),
|
|
},
|
|
"index 3": {
|
|
input: cty.TupleVal([]cty.Value{cty.StringVal("one"), cty.NumberIntVal(2.0), cty.NumberIntVal(3), cty.StringVal("four")}),
|
|
key: cty.StringVal("four"),
|
|
want: cty.NumberIntVal(3),
|
|
},
|
|
"index -1": {
|
|
input: cty.TupleVal([]cty.Value{cty.StringVal("one"), cty.NumberIntVal(2.0), cty.NumberIntVal(3), cty.StringVal("four")}),
|
|
key: cty.StringVal("3"),
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
got, err := indexOfFunc().Call([]cty.Value{test.input, test.key})
|
|
if test.wantErr {
|
|
require.Error(t, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
require.Equal(t, test.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBasename(t *testing.T) {
|
|
type testCase struct {
|
|
input cty.Value
|
|
want cty.Value
|
|
wantErr bool
|
|
}
|
|
tests := map[string]testCase{
|
|
"empty": {
|
|
input: cty.StringVal(""),
|
|
want: cty.StringVal("."),
|
|
},
|
|
"slash": {
|
|
input: cty.StringVal("/"),
|
|
want: cty.StringVal("/"),
|
|
},
|
|
"simple": {
|
|
input: cty.StringVal("/foo/bar"),
|
|
want: cty.StringVal("bar"),
|
|
},
|
|
"simple no slash": {
|
|
input: cty.StringVal("foo/bar"),
|
|
want: cty.StringVal("bar"),
|
|
},
|
|
"dot": {
|
|
input: cty.StringVal("/foo/bar."),
|
|
want: cty.StringVal("bar."),
|
|
},
|
|
"dotdot": {
|
|
input: cty.StringVal("/foo/bar.."),
|
|
want: cty.StringVal("bar.."),
|
|
},
|
|
"dotdotdot": {
|
|
input: cty.StringVal("/foo/bar..."),
|
|
want: cty.StringVal("bar..."),
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
got, err := basenameFunc().Call([]cty.Value{test.input})
|
|
if test.wantErr {
|
|
require.Error(t, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
require.Equal(t, test.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDirname(t *testing.T) {
|
|
type testCase struct {
|
|
input cty.Value
|
|
want cty.Value
|
|
wantErr bool
|
|
}
|
|
tests := map[string]testCase{
|
|
"empty": {
|
|
input: cty.StringVal(""),
|
|
want: cty.StringVal("."),
|
|
},
|
|
"slash": {
|
|
input: cty.StringVal("/"),
|
|
want: cty.StringVal("/"),
|
|
},
|
|
"simple": {
|
|
input: cty.StringVal("/foo/bar"),
|
|
want: cty.StringVal("/foo"),
|
|
},
|
|
"simple no slash": {
|
|
input: cty.StringVal("foo/bar"),
|
|
want: cty.StringVal("foo"),
|
|
},
|
|
"dot": {
|
|
input: cty.StringVal("/foo/bar."),
|
|
want: cty.StringVal("/foo"),
|
|
},
|
|
"dotdot": {
|
|
input: cty.StringVal("/foo/bar.."),
|
|
want: cty.StringVal("/foo"),
|
|
},
|
|
"dotdotdot": {
|
|
input: cty.StringVal("/foo/bar..."),
|
|
want: cty.StringVal("/foo"),
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
got, err := dirnameFunc().Call([]cty.Value{test.input})
|
|
if test.wantErr {
|
|
require.Error(t, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
require.Equal(t, test.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSanitize(t *testing.T) {
|
|
type testCase struct {
|
|
input cty.Value
|
|
want cty.Value
|
|
}
|
|
tests := map[string]testCase{
|
|
"empty": {
|
|
input: cty.StringVal(""),
|
|
want: cty.StringVal(""),
|
|
},
|
|
"simple": {
|
|
input: cty.StringVal("foo/bar"),
|
|
want: cty.StringVal("foo_bar"),
|
|
},
|
|
"simple no slash": {
|
|
input: cty.StringVal("foobar"),
|
|
want: cty.StringVal("foobar"),
|
|
},
|
|
"dot": {
|
|
input: cty.StringVal("foo/bar."),
|
|
want: cty.StringVal("foo_bar_"),
|
|
},
|
|
"dotdot": {
|
|
input: cty.StringVal("foo/bar.."),
|
|
want: cty.StringVal("foo_bar__"),
|
|
},
|
|
"dotdotdot": {
|
|
input: cty.StringVal("foo/bar..."),
|
|
want: cty.StringVal("foo_bar___"),
|
|
},
|
|
"utf8": {
|
|
input: cty.StringVal("foo/🍕bar"),
|
|
want: cty.StringVal("foo__bar"),
|
|
},
|
|
"symbols": {
|
|
input: cty.StringVal("foo/bar!@(ba+z)"),
|
|
want: cty.StringVal("foo_bar___ba_z_"),
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
got, err := sanitizeFunc().Call([]cty.Value{test.input})
|
|
require.NoError(t, err)
|
|
require.Equal(t, test.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestHomedir(t *testing.T) {
|
|
home, err := homedirFunc().Call(nil)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, home.AsString())
|
|
require.True(t, filepath.IsAbs(home.AsString()))
|
|
}
|
|
|
|
func TestSemverCmp(t *testing.T) {
|
|
type testCase struct {
|
|
version cty.Value
|
|
constraint cty.Value
|
|
want cty.Value
|
|
wantErr bool
|
|
}
|
|
tests := map[string]testCase{
|
|
"valid constraint satisfied": {
|
|
version: cty.StringVal("1.2.3"),
|
|
constraint: cty.StringVal(">= 1.0.0"),
|
|
want: cty.BoolVal(true),
|
|
},
|
|
"valid constraint not satisfied": {
|
|
version: cty.StringVal("2.1.0"),
|
|
constraint: cty.StringVal("< 2.0.0"),
|
|
want: cty.BoolVal(false),
|
|
},
|
|
"valid constraint satisfied without patch": {
|
|
version: cty.StringVal("3.22"),
|
|
constraint: cty.StringVal(">= 3.20"),
|
|
want: cty.BoolVal(true),
|
|
},
|
|
"invalid version": {
|
|
version: cty.StringVal("not-a-version"),
|
|
constraint: cty.StringVal(">= 1.0.0"),
|
|
wantErr: true,
|
|
},
|
|
"invalid constraint": {
|
|
version: cty.StringVal("1.2.3"),
|
|
constraint: cty.StringVal("not-a-constraint"),
|
|
wantErr: true,
|
|
},
|
|
"empty version": {
|
|
version: cty.StringVal(""),
|
|
constraint: cty.StringVal(">= 1.0.0"),
|
|
wantErr: true,
|
|
},
|
|
"empty constraint": {
|
|
version: cty.StringVal("1.2.3"),
|
|
constraint: cty.StringVal(""),
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
got, err := semvercmpFunc().Call([]cty.Value{test.version, test.constraint})
|
|
if test.wantErr {
|
|
require.Error(t, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
require.Equal(t, test.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnixTimestampParseFunc(t *testing.T) {
|
|
type testCase struct {
|
|
input cty.Value
|
|
want map[string]cty.Value
|
|
wantErr bool
|
|
}
|
|
tests := map[string]testCase{
|
|
"positive timestamp": {
|
|
input: cty.NumberIntVal(1690328596),
|
|
want: map[string]cty.Value{
|
|
"year": cty.NumberIntVal(2023),
|
|
"year_day": cty.NumberIntVal(206),
|
|
"day": cty.NumberIntVal(25),
|
|
"month": cty.NumberIntVal(7),
|
|
"month_name": cty.StringVal("July"),
|
|
"weekday": cty.NumberIntVal(2),
|
|
"weekday_name": cty.StringVal("Tuesday"),
|
|
"hour": cty.NumberIntVal(23),
|
|
"minute": cty.NumberIntVal(43),
|
|
"second": cty.NumberIntVal(16),
|
|
"rfc3339": cty.StringVal("2023-07-25T23:43:16Z"),
|
|
"iso_year": cty.NumberIntVal(2023),
|
|
"iso_week": cty.NumberIntVal(30),
|
|
},
|
|
},
|
|
"zero timestamp": {
|
|
input: cty.NumberIntVal(0),
|
|
want: map[string]cty.Value{
|
|
"year": cty.NumberIntVal(1970),
|
|
"year_day": cty.NumberIntVal(1),
|
|
"day": cty.NumberIntVal(1),
|
|
"month": cty.NumberIntVal(1),
|
|
"month_name": cty.StringVal("January"),
|
|
"weekday": cty.NumberIntVal(4),
|
|
"weekday_name": cty.StringVal("Thursday"),
|
|
"hour": cty.NumberIntVal(0),
|
|
"minute": cty.NumberIntVal(0),
|
|
"second": cty.NumberIntVal(0),
|
|
"rfc3339": cty.StringVal("1970-01-01T00:00:00Z"),
|
|
"iso_year": cty.NumberIntVal(1970),
|
|
"iso_week": cty.NumberIntVal(1),
|
|
},
|
|
},
|
|
"negative timestamp": {
|
|
input: cty.NumberIntVal(-1),
|
|
want: map[string]cty.Value{
|
|
"year": cty.NumberIntVal(1969),
|
|
"year_day": cty.NumberIntVal(365),
|
|
"day": cty.NumberIntVal(31),
|
|
"month": cty.NumberIntVal(12),
|
|
"month_name": cty.StringVal("December"),
|
|
"weekday": cty.NumberIntVal(3),
|
|
"weekday_name": cty.StringVal("Wednesday"),
|
|
"hour": cty.NumberIntVal(23),
|
|
"minute": cty.NumberIntVal(59),
|
|
"second": cty.NumberIntVal(59),
|
|
"rfc3339": cty.StringVal("1969-12-31T23:59:59Z"),
|
|
"iso_year": cty.NumberIntVal(1970),
|
|
"iso_week": cty.NumberIntVal(1),
|
|
},
|
|
},
|
|
"fractional timestamp": {
|
|
input: cty.NumberFloatVal(1.2),
|
|
wantErr: true,
|
|
},
|
|
"string timestamp": {
|
|
input: cty.StringVal("0"),
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
got, err := unixtimestampParseFunc().Call([]cty.Value{test.input})
|
|
if test.wantErr {
|
|
require.Error(t, err)
|
|
return
|
|
}
|
|
require.NoError(t, err)
|
|
for k, v := range test.want {
|
|
require.True(t, got.GetAttr(k).RawEquals(v), "field %s: got %v, want %v", k, got.GetAttr(k), v)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFormatTimestampFunc(t *testing.T) {
|
|
type testCase struct {
|
|
format cty.Value
|
|
input cty.Value
|
|
want cty.Value
|
|
wantErr bool
|
|
}
|
|
tests := map[string]testCase{
|
|
"unix format from rfc3339 string": {
|
|
format: cty.StringVal("X"),
|
|
input: cty.StringVal("2015-10-21T00:00:00Z"),
|
|
want: cty.StringVal("1445385600"),
|
|
},
|
|
"unix format from unix timestamp input": {
|
|
format: cty.StringVal("X"),
|
|
input: cty.NumberIntVal(1445385600),
|
|
want: cty.StringVal("1445385600"),
|
|
},
|
|
"rfc3339 string input": {
|
|
format: cty.StringVal("YYYY-MM-DD"),
|
|
input: cty.StringVal("2025-09-16T12:00:00Z"),
|
|
want: cty.StringVal("2025-09-16"),
|
|
},
|
|
"unix timestamp input": {
|
|
format: cty.StringVal("YYYY-MM-DD'T'hh:mm:ssZ"),
|
|
input: cty.NumberIntVal(1690328596),
|
|
want: cty.StringVal("2023-07-25T23:43:16Z"),
|
|
},
|
|
"negative unix timestamp input": {
|
|
format: cty.StringVal("YYYY-MM-DD'T'hh:mm:ssZ"),
|
|
input: cty.NumberIntVal(-1),
|
|
want: cty.StringVal("1969-12-31T23:59:59Z"),
|
|
},
|
|
"fractional unix timestamp input": {
|
|
format: cty.StringVal("YYYY-MM-DD"),
|
|
input: cty.NumberFloatVal(1.2),
|
|
wantErr: true,
|
|
},
|
|
"invalid string input": {
|
|
format: cty.StringVal("YYYY-MM-DD"),
|
|
input: cty.StringVal("0"),
|
|
wantErr: true,
|
|
},
|
|
"invalid string input for unix format": {
|
|
format: cty.StringVal("X"),
|
|
input: cty.StringVal("0"),
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
got, err := formatTimestampFunc().Call([]cty.Value{test.format, test.input})
|
|
if test.wantErr {
|
|
require.Error(t, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
require.Equal(t, test.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|