opentofu/lang/functions_test.go
Arthur Burkart d4716a69e1
lang/funcs: "anytrue" function
This is an analog to the "alltrue" function, using OR as the reduce
operator rather than AND.

This also includes some simplification of the "alltrue" implementation
to implement it similarly as a sort of reduce operation with AND
as the reduce operator, but with the same effective behavior.
2020-10-23 13:52:48 -07:00

1138 lines
24 KiB
Go

package lang
import (
"fmt"
"os"
"path/filepath"
"testing"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
homedir "github.com/mitchellh/go-homedir"
"github.com/zclconf/go-cty/cty"
)
// TestFunctions tests that functions are callable through the functionality
// in the langs package, via HCL.
//
// These tests are primarily here to assert that the functions are properly
// registered in the functions table, rather than to test all of the details
// of the functions. Each function should only have one or two tests here,
// since the main set of unit tests for a function should live alongside that
// function either in the "funcs" subdirectory here or over in the cty
// function/stdlib package.
//
// One exception to that is we can use this test mechanism to assert common
// patterns that are used in real-world configurations which rely on behaviors
// implemented either in this lang package or in HCL itself, such as automatic
// type conversions. The function unit tests don't cover those things because
// they call directly into the functions.
//
// With that said then, this test function should contain at least one simple
// test case per function registered in the functions table (just to prove
// it really is registered correctly) and possibly a small set of additional
// functions showing real-world use-cases that rely on type conversion
// behaviors.
func TestFunctions(t *testing.T) {
// used in `pathexpand()` test
homePath, err := homedir.Dir()
if err != nil {
t.Fatalf("Error getting home directory: %v", err)
}
tests := map[string][]struct {
src string
want cty.Value
}{
// Please maintain this list in alphabetical order by function, with
// a blank line between the group of tests for each function.
"abs": {
{
`abs(-1)`,
cty.NumberIntVal(1),
},
},
"abspath": {
{
`abspath(".")`,
cty.StringVal((func() string {
cwd, err := os.Getwd()
if err != nil {
panic(err)
}
return cwd
})()),
},
},
"alltrue": {
{
`alltrue(["true", true])`,
cty.True,
},
},
"anytrue": {
{
`anytrue([])`,
cty.False,
},
},
"base64decode": {
{
`base64decode("YWJjMTIzIT8kKiYoKSctPUB+")`,
cty.StringVal("abc123!?$*&()'-=@~"),
},
},
"base64encode": {
{
`base64encode("abc123!?$*&()'-=@~")`,
cty.StringVal("YWJjMTIzIT8kKiYoKSctPUB+"),
},
},
"base64gzip": {
{
`base64gzip("test")`,
cty.StringVal("H4sIAAAAAAAA/ypJLS4BAAAA//8BAAD//wx+f9gEAAAA"),
},
},
"base64sha256": {
{
`base64sha256("test")`,
cty.StringVal("n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg="),
},
},
"base64sha512": {
{
`base64sha512("test")`,
cty.StringVal("7iaw3Ur350mqGo7jwQrpkj9hiYB3Lkc/iBml1JQODbJ6wYX4oOHV+E+IvIh/1nsUNzLDBMxfqa2Ob1f1ACio/w=="),
},
},
"basename": {
{
`basename("testdata/hello.txt")`,
cty.StringVal("hello.txt"),
},
},
"can": {
{
`can(true)`,
cty.True,
},
{
// Note: "can" only works with expressions that pass static
// validation, because it only gets an opportunity to run in
// that case. The following "works" (captures the error) because
// Terraform understands it as a reference to an attribute
// that does not exist during dynamic evaluation.
//
// "can" doesn't work with references that could never possibly
// be valid and are thus caught during static validation, such
// as an expression like "foo" alone which would be understood
// as an invalid resource reference.
`can({}.baz)`,
cty.False,
},
},
"ceil": {
{
`ceil(1.2)`,
cty.NumberIntVal(2),
},
},
"chomp": {
{
`chomp("goodbye\ncruel\nworld\n")`,
cty.StringVal("goodbye\ncruel\nworld"),
},
},
"chunklist": {
{
`chunklist(["a", "b", "c"], 1)`,
cty.ListVal([]cty.Value{
cty.ListVal([]cty.Value{
cty.StringVal("a"),
}),
cty.ListVal([]cty.Value{
cty.StringVal("b"),
}),
cty.ListVal([]cty.Value{
cty.StringVal("c"),
}),
}),
},
},
"cidrhost": {
{
`cidrhost("192.168.1.0/24", 5)`,
cty.StringVal("192.168.1.5"),
},
},
"cidrnetmask": {
{
`cidrnetmask("192.168.1.0/24")`,
cty.StringVal("255.255.255.0"),
},
},
"cidrsubnet": {
{
`cidrsubnet("192.168.2.0/20", 4, 6)`,
cty.StringVal("192.168.6.0/24"),
},
},
"cidrsubnets": {
{
`cidrsubnets("10.0.0.0/8", 8, 8, 16, 8)`,
cty.ListVal([]cty.Value{
cty.StringVal("10.0.0.0/16"),
cty.StringVal("10.1.0.0/16"),
cty.StringVal("10.2.0.0/24"),
cty.StringVal("10.3.0.0/16"),
}),
},
},
"coalesce": {
{
`coalesce("first", "second", "third")`,
cty.StringVal("first"),
},
{
`coalescelist(["first", "second"], ["third", "fourth"])`,
cty.TupleVal([]cty.Value{
cty.StringVal("first"), cty.StringVal("second"),
}),
},
},
"coalescelist": {
{
`coalescelist(list("a", "b"), list("c", "d"))`,
cty.ListVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("b"),
}),
},
{
`coalescelist(["a", "b"], ["c", "d"])`,
cty.TupleVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("b"),
}),
},
},
"compact": {
{
`compact(["test", "", "test"])`,
cty.ListVal([]cty.Value{
cty.StringVal("test"), cty.StringVal("test"),
}),
},
},
"concat": {
{
`concat(["a", ""], ["b", "c"])`,
cty.TupleVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal(""),
cty.StringVal("b"),
cty.StringVal("c"),
}),
},
},
"contains": {
{
`contains(["a", "b"], "a")`,
cty.True,
},
{ // Should also work with sets, due to automatic conversion
`contains(toset(["a", "b"]), "a")`,
cty.True,
},
},
"csvdecode": {
{
`csvdecode("a,b,c\n1,2,3\n4,5,6")`,
cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"a": cty.StringVal("1"),
"b": cty.StringVal("2"),
"c": cty.StringVal("3"),
}),
cty.ObjectVal(map[string]cty.Value{
"a": cty.StringVal("4"),
"b": cty.StringVal("5"),
"c": cty.StringVal("6"),
}),
}),
},
},
"dirname": {
{
`dirname("testdata/hello.txt")`,
cty.StringVal("testdata"),
},
},
"distinct": {
{
`distinct(["a", "b", "a", "b"])`,
cty.ListVal([]cty.Value{
cty.StringVal("a"), cty.StringVal("b"),
}),
},
},
"element": {
{
`element(["hello"], 0)`,
cty.StringVal("hello"),
},
},
"file": {
{
`file("hello.txt")`,
cty.StringVal("hello!"),
},
},
"fileexists": {
{
`fileexists("hello.txt")`,
cty.BoolVal(true),
},
},
"fileset": {
{
`fileset(".", "*/hello.*")`,
cty.SetVal([]cty.Value{
cty.StringVal("subdirectory/hello.tmpl"),
cty.StringVal("subdirectory/hello.txt"),
}),
},
{
`fileset(".", "subdirectory/hello.*")`,
cty.SetVal([]cty.Value{
cty.StringVal("subdirectory/hello.tmpl"),
cty.StringVal("subdirectory/hello.txt"),
}),
},
{
`fileset(".", "hello.*")`,
cty.SetVal([]cty.Value{
cty.StringVal("hello.tmpl"),
cty.StringVal("hello.txt"),
}),
},
{
`fileset("subdirectory", "hello.*")`,
cty.SetVal([]cty.Value{
cty.StringVal("hello.tmpl"),
cty.StringVal("hello.txt"),
}),
},
},
"filebase64": {
{
`filebase64("hello.txt")`,
cty.StringVal("aGVsbG8h"),
},
},
"filebase64sha256": {
{
`filebase64sha256("hello.txt")`,
cty.StringVal("zgYJL7lI2f+sfRo3bkBLJrdXW8wR7gWkYV/vT+w6MIs="),
},
},
"filebase64sha512": {
{
`filebase64sha512("hello.txt")`,
cty.StringVal("xvgdsOn4IGyXHJ5YJuO6gj/7saOpAPgEdlKov3jqmP38dFhVo4U6Y1Z1RY620arxIJ6I6tLRkjgrXEy91oUOAg=="),
},
},
"filemd5": {
{
`filemd5("hello.txt")`,
cty.StringVal("5a8dd3ad0756a93ded72b823b19dd877"),
},
},
"filesha1": {
{
`filesha1("hello.txt")`,
cty.StringVal("8f7d88e901a5ad3a05d8cc0de93313fd76028f8c"),
},
},
"filesha256": {
{
`filesha256("hello.txt")`,
cty.StringVal("ce06092fb948d9ffac7d1a376e404b26b7575bcc11ee05a4615fef4fec3a308b"),
},
},
"filesha512": {
{
`filesha512("hello.txt")`,
cty.StringVal("c6f81db0e9f8206c971c9e5826e3ba823ffbb1a3a900f8047652a8bf78ea98fdfc745855a3853a635675458eb6d1aaf1209e88ead2d192382b5c4cbdd6850e02"),
},
},
"flatten": {
{
`flatten([["a", "b"], ["c", "d"]])`,
cty.TupleVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("b"),
cty.StringVal("c"),
cty.StringVal("d"),
}),
},
},
"floor": {
{
`floor(-1.8)`,
cty.NumberFloatVal(-2),
},
},
"format": {
{
`format("Hello, %s!", "Ander")`,
cty.StringVal("Hello, Ander!"),
},
},
"formatlist": {
{
`formatlist("Hello, %s!", ["Valentina", "Ander", "Olivia", "Sam"])`,
cty.ListVal([]cty.Value{
cty.StringVal("Hello, Valentina!"),
cty.StringVal("Hello, Ander!"),
cty.StringVal("Hello, Olivia!"),
cty.StringVal("Hello, Sam!"),
}),
},
},
"formatdate": {
{
`formatdate("DD MMM YYYY hh:mm ZZZ", "2018-01-04T23:12:01Z")`,
cty.StringVal("04 Jan 2018 23:12 UTC"),
},
},
"indent": {
{
fmt.Sprintf("indent(4, %#v)", Poem),
cty.StringVal("Fleas:\n Adam\n Had'em\n \n E.E. Cummings"),
},
},
"index": {
{
`index(["a", "b", "c"], "a")`,
cty.NumberIntVal(0),
},
},
"join": {
{
`join(" ", ["Hello", "World"])`,
cty.StringVal("Hello World"),
},
},
"jsondecode": {
{
`jsondecode("{\"hello\": \"world\"}")`,
cty.ObjectVal(map[string]cty.Value{
"hello": cty.StringVal("world"),
}),
},
},
"jsonencode": {
{
`jsonencode({"hello"="world"})`,
cty.StringVal("{\"hello\":\"world\"}"),
},
// We are intentionally choosing to escape <, >, and & characters
// to preserve backwards compatibility with Terraform 0.11
{
`jsonencode({"hello"="<cats & kittens>"})`,
cty.StringVal("{\"hello\":\"\\u003ccats \\u0026 kittens\\u003e\"}"),
},
},
"keys": {
{
`keys({"hello"=1, "goodbye"=42})`,
cty.TupleVal([]cty.Value{
cty.StringVal("goodbye"),
cty.StringVal("hello"),
}),
},
},
"length": {
{
`length(["the", "quick", "brown", "bear"])`,
cty.NumberIntVal(4),
},
},
"list": {
{
`list("hello")`,
cty.ListVal([]cty.Value{
cty.StringVal("hello"),
}),
},
},
"log": {
{
`log(1, 10)`,
cty.NumberFloatVal(0),
},
},
"lookup": {
{
`lookup({hello=1, goodbye=42}, "goodbye")`,
cty.NumberIntVal(42),
},
},
"lower": {
{
`lower("HELLO")`,
cty.StringVal("hello"),
},
},
"map": {
{
`map("hello", "world")`,
cty.MapVal(map[string]cty.Value{
"hello": cty.StringVal("world"),
}),
},
},
"matchkeys": {
{
`matchkeys(["a", "b", "c"], ["ref1", "ref2", "ref3"], ["ref1"])`,
cty.ListVal([]cty.Value{
cty.StringVal("a"),
}),
},
{ // mixing types in searchset
`matchkeys(["a", "b", "c"], [1, 2, 3], [1, "3"])`,
cty.ListVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("c"),
}),
},
},
"max": {
{
`max(12, 54, 3)`,
cty.NumberIntVal(54),
},
},
"md5": {
{
`md5("tada")`,
cty.StringVal("ce47d07243bb6eaf5e1322c81baf9bbf"),
},
},
"merge": {
{
`merge({"a"="b"}, {"c"="d"})`,
cty.ObjectVal(map[string]cty.Value{
"a": cty.StringVal("b"),
"c": cty.StringVal("d"),
}),
},
},
"min": {
{
`min(12, 54, 3)`,
cty.NumberIntVal(3),
},
},
"parseint": {
{
`parseint("100", 10)`,
cty.NumberIntVal(100),
},
},
"pathexpand": {
{
`pathexpand("~/test-file")`,
cty.StringVal(filepath.Join(homePath, "test-file")),
},
},
"pow": {
{
`pow(1,0)`,
cty.NumberFloatVal(1),
},
},
"range": {
{
`range(3)`,
cty.ListVal([]cty.Value{
cty.NumberIntVal(0),
cty.NumberIntVal(1),
cty.NumberIntVal(2),
}),
},
{
`range(1, 4)`,
cty.ListVal([]cty.Value{
cty.NumberIntVal(1),
cty.NumberIntVal(2),
cty.NumberIntVal(3),
}),
},
{
`range(1, 8, 2)`,
cty.ListVal([]cty.Value{
cty.NumberIntVal(1),
cty.NumberIntVal(3),
cty.NumberIntVal(5),
cty.NumberIntVal(7),
}),
},
},
"regex": {
{
`regex("(\\d+)([a-z]+)", "aaa111bbb222")`,
cty.TupleVal([]cty.Value{cty.StringVal("111"), cty.StringVal("bbb")}),
},
},
"regexall": {
{
`regexall("(\\d+)([a-z]+)", "...111aaa222bbb...")`,
cty.ListVal([]cty.Value{
cty.TupleVal([]cty.Value{cty.StringVal("111"), cty.StringVal("aaa")}),
cty.TupleVal([]cty.Value{cty.StringVal("222"), cty.StringVal("bbb")}),
}),
},
},
"replace": {
{
`replace("hello", "hel", "bel")`,
cty.StringVal("bello"),
},
},
"reverse": {
{
`reverse(["a", true, 0])`,
cty.TupleVal([]cty.Value{cty.Zero, cty.True, cty.StringVal("a")}),
},
},
"rsadecrypt": {
{
fmt.Sprintf("rsadecrypt(%#v, %#v)", CipherBase64, PrivateKey),
cty.StringVal("message"),
},
},
"setintersection": {
{
`setintersection(["a", "b"], ["b", "c"], ["b", "d"])`,
cty.SetVal([]cty.Value{
cty.StringVal("b"),
}),
},
},
"setproduct": {
{
`setproduct(["development", "staging", "production"], ["app1", "app2"])`,
cty.ListVal([]cty.Value{
cty.TupleVal([]cty.Value{cty.StringVal("development"), cty.StringVal("app1")}),
cty.TupleVal([]cty.Value{cty.StringVal("development"), cty.StringVal("app2")}),
cty.TupleVal([]cty.Value{cty.StringVal("staging"), cty.StringVal("app1")}),
cty.TupleVal([]cty.Value{cty.StringVal("staging"), cty.StringVal("app2")}),
cty.TupleVal([]cty.Value{cty.StringVal("production"), cty.StringVal("app1")}),
cty.TupleVal([]cty.Value{cty.StringVal("production"), cty.StringVal("app2")}),
}),
},
},
"setsubtract": {
{
`setsubtract(["a", "b", "c"], ["a", "c"])`,
cty.SetVal([]cty.Value{
cty.StringVal("b"),
}),
},
},
"setunion": {
{
`setunion(["a", "b"], ["b", "c"], ["d"])`,
cty.SetVal([]cty.Value{
cty.StringVal("d"),
cty.StringVal("b"),
cty.StringVal("a"),
cty.StringVal("c"),
}),
},
},
"sha1": {
{
`sha1("test")`,
cty.StringVal("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"),
},
},
"sha256": {
{
`sha256("test")`,
cty.StringVal("9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"),
},
},
"sha512": {
{
`sha512("test")`,
cty.StringVal("ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff"),
},
},
"signum": {
{
`signum(12)`,
cty.NumberFloatVal(1),
},
},
"slice": {
{
// force a list type here for testing
`slice(list("a", "b", "c", "d"), 1, 3)`,
cty.ListVal([]cty.Value{
cty.StringVal("b"), cty.StringVal("c"),
}),
},
{
`slice(["a", "b", 3, 4], 1, 3)`,
cty.TupleVal([]cty.Value{
cty.StringVal("b"), cty.NumberIntVal(3),
}),
},
},
"sort": {
{
`sort(["banana", "apple"])`,
cty.ListVal([]cty.Value{
cty.StringVal("apple"),
cty.StringVal("banana"),
}),
},
},
"split": {
{
`split(" ", "Hello World")`,
cty.ListVal([]cty.Value{
cty.StringVal("Hello"),
cty.StringVal("World"),
}),
},
},
"strrev": {
{
`strrev("hello world")`,
cty.StringVal("dlrow olleh"),
},
},
"substr": {
{
`substr("hello world", 1, 4)`,
cty.StringVal("ello"),
},
},
"sum": {
{
`sum([2340.5,10,3])`,
cty.NumberFloatVal(2353.5),
},
},
"textdecodebase64": {
{
`textdecodebase64("dABlAHMAdAA=", "UTF-16LE")`,
cty.StringVal("test"),
},
},
"textencodebase64": {
{
`textencodebase64("test", "UTF-16LE")`,
cty.StringVal("dABlAHMAdAA="),
},
},
"templatefile": {
{
`templatefile("hello.tmpl", {name = "Jodie"})`,
cty.StringVal("Hello, Jodie!"),
},
},
"timeadd": {
{
`timeadd("2017-11-22T00:00:00Z", "1s")`,
cty.StringVal("2017-11-22T00:00:01Z"),
},
},
"title": {
{
`title("hello")`,
cty.StringVal("Hello"),
},
},
"tobool": {
{
`tobool("false")`,
cty.False,
},
},
"tolist": {
{
`tolist(["a", "b", "c"])`,
cty.ListVal([]cty.Value{
cty.StringVal("a"), cty.StringVal("b"), cty.StringVal("c"),
}),
},
},
"tomap": {
{
`tomap({"a" = 1, "b" = 2})`,
cty.MapVal(map[string]cty.Value{
"a": cty.NumberIntVal(1),
"b": cty.NumberIntVal(2),
}),
},
},
"tonumber": {
{
`tonumber("42")`,
cty.NumberIntVal(42),
},
},
"toset": {
{
`toset(["a", "b", "c"])`,
cty.SetVal([]cty.Value{
cty.StringVal("a"), cty.StringVal("b"), cty.StringVal("c"),
}),
},
},
"tostring": {
{
`tostring("a")`,
cty.StringVal("a"),
},
},
"transpose": {
{
`transpose({"a" = ["1", "2"], "b" = ["2", "3"]})`,
cty.MapVal(map[string]cty.Value{
"1": cty.ListVal([]cty.Value{cty.StringVal("a")}),
"2": cty.ListVal([]cty.Value{cty.StringVal("a"), cty.StringVal("b")}),
"3": cty.ListVal([]cty.Value{cty.StringVal("b")}),
}),
},
},
"trim": {
{
`trim("?!hello?!", "!?")`,
cty.StringVal("hello"),
},
},
"trimprefix": {
{
`trimprefix("helloworld", "hello")`,
cty.StringVal("world"),
},
},
"trimspace": {
{
`trimspace(" hello ")`,
cty.StringVal("hello"),
},
},
"trimsuffix": {
{
`trimsuffix("helloworld", "world")`,
cty.StringVal("hello"),
},
},
"try": {
{
// Note: "try" only works with expressions that pass static
// validation, because it only gets an opportunity to run in
// that case. The following "works" (captures the error) because
// Terraform understands it as a reference to an attribute
// that does not exist during dynamic evaluation.
//
// "try" doesn't work with references that could never possibly
// be valid and are thus caught during static validation, such
// as an expression like "foo" alone which would be understood
// as an invalid resource reference. That's okay because this
// function exists primarily to ease access to dynamically-typed
// structures that Terraform can't statically validate by
// definition.
`try({}.baz, "fallback")`,
cty.StringVal("fallback"),
},
{
`try("fallback")`,
cty.StringVal("fallback"),
},
},
"upper": {
{
`upper("hello")`,
cty.StringVal("HELLO"),
},
},
"urlencode": {
{
`urlencode("foo:bar@localhost?foo=bar&bar=baz")`,
cty.StringVal("foo%3Abar%40localhost%3Ffoo%3Dbar%26bar%3Dbaz"),
},
},
"uuidv5": {
{
`uuidv5("dns", "tada")`,
cty.StringVal("faa898db-9b9d-5b75-86a9-149e7bb8e3b8"),
},
{
`uuidv5("url", "tada")`,
cty.StringVal("2c1ff6b4-211f-577e-94de-d978b0caa16e"),
},
{
`uuidv5("oid", "tada")`,
cty.StringVal("61eeea26-5176-5288-87fc-232d6ed30d2f"),
},
{
`uuidv5("x500", "tada")`,
cty.StringVal("7e12415e-f7c9-57c3-9e43-52dc9950d264"),
},
{
`uuidv5("6ba7b810-9dad-11d1-80b4-00c04fd430c8", "tada")`,
cty.StringVal("faa898db-9b9d-5b75-86a9-149e7bb8e3b8"),
},
},
"values": {
{
`values({"hello"="world", "what's"="up"})`,
cty.TupleVal([]cty.Value{
cty.StringVal("world"),
cty.StringVal("up"),
}),
},
},
"yamldecode": {
{
`yamldecode("true")`,
cty.True,
},
{
`yamldecode("key: 0ba")`,
cty.ObjectVal(map[string]cty.Value{
"key": cty.StringVal("0ba"),
}),
},
},
"yamlencode": {
{
`yamlencode(["foo", "bar", true])`,
cty.StringVal("- \"foo\"\n- \"bar\"\n- true\n"),
},
{
`yamlencode({a = "b", c = "d"})`,
cty.StringVal("\"a\": \"b\"\n\"c\": \"d\"\n"),
},
{
`yamlencode(true)`,
// the ... here is an "end of document" marker, produced for implied primitive types only
cty.StringVal("true\n...\n"),
},
},
"zipmap": {
{
`zipmap(["hello", "bar"], ["world", "baz"])`,
cty.ObjectVal(map[string]cty.Value{
"hello": cty.StringVal("world"),
"bar": cty.StringVal("baz"),
}),
},
},
}
data := &dataForTests{} // no variables available; we only need literals here
scope := &Scope{
Data: data,
BaseDir: "./testdata/functions-test", // for the functions that read from the filesystem
}
// Check that there is at least one test case for each function, omitting
// those functions that do not return consistent values
allFunctions := scope.Functions()
// TODO: we can test the impure functions partially by configuring the scope
// with PureOnly: true and then verify that they return unknown values of a
// suitable type.
for _, impureFunc := range impureFunctions {
delete(allFunctions, impureFunc)
}
for f, _ := range scope.Functions() {
if _, ok := tests[f]; !ok {
t.Errorf("Missing test for function %s\n", f)
}
}
for funcName, funcTests := range tests {
t.Run(funcName, func(t *testing.T) {
for _, test := range funcTests {
t.Run(test.src, func(t *testing.T) {
expr, parseDiags := hclsyntax.ParseExpression([]byte(test.src), "test.hcl", hcl.Pos{Line: 1, Column: 1})
if parseDiags.HasErrors() {
for _, diag := range parseDiags {
t.Error(diag.Error())
}
return
}
got, diags := scope.EvalExpr(expr, cty.DynamicPseudoType)
if diags.HasErrors() {
for _, diag := range diags {
t.Errorf("%s: %s", diag.Description().Summary, diag.Description().Detail)
}
return
}
if !test.want.RawEquals(got) {
t.Errorf("wrong result\nexpr: %s\ngot: %#v\nwant: %#v", test.src, got, test.want)
}
})
}
})
}
}
const (
CipherBase64 = "eczGaDhXDbOFRZGhjx2etVzWbRqWDlmq0bvNt284JHVbwCgObiuyX9uV0LSAMY707IEgMkExJqXmsB4OWKxvB7epRB9G/3+F+pcrQpODlDuL9oDUAsa65zEpYF0Wbn7Oh7nrMQncyUPpyr9WUlALl0gRWytOA23S+y5joa4M34KFpawFgoqTu/2EEH4Xl1zo+0fy73fEto+nfkUY+meuyGZ1nUx/+DljP7ZqxHBFSlLODmtuTMdswUbHbXbWneW51D7Jm7xB8nSdiA2JQNK5+Sg5x8aNfgvFTt/m2w2+qpsyFa5Wjeu6fZmXSl840CA07aXbk9vN4I81WmJyblD/ZA=="
PrivateKey = `
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAgUElV5mwqkloIrM8ZNZ72gSCcnSJt7+/Usa5G+D15YQUAdf9
c1zEekTfHgDP+04nw/uFNFaE5v1RbHaPxhZYVg5ZErNCa/hzn+x10xzcepeS3KPV
Xcxae4MR0BEegvqZqJzN9loXsNL/c3H/B+2Gle3hTxjlWFb3F5qLgR+4Mf4ruhER
1v6eHQa/nchi03MBpT4UeJ7MrL92hTJYLdpSyCqmr8yjxkKJDVC2uRrr+sTSxfh7
r6v24u/vp/QTmBIAlNPgadVAZw17iNNb7vjV7Gwl/5gHXonCUKURaV++dBNLrHIZ
pqcAM8wHRph8mD1EfL9hsz77pHewxolBATV+7QIDAQABAoIBAC1rK+kFW3vrAYm3
+8/fQnQQw5nec4o6+crng6JVQXLeH32qXShNf8kLLG/Jj0vaYcTPPDZw9JCKkTMQ
0mKj9XR/5DLbBMsV6eNXXuvJJ3x4iKW5eD9WkLD4FKlNarBRyO7j8sfPTqXW7uat
NxWdFH7YsSRvNh/9pyQHLWA5OituidMrYbc3EUx8B1GPNyJ9W8Q8znNYLfwYOjU4
Wv1SLE6qGQQH9Q0WzA2WUf8jklCYyMYTIywAjGb8kbAJlKhmj2t2Igjmqtwt1PYc
pGlqbtQBDUiWXt5S4YX/1maIQ/49yeNUajjpbJiH3DbhJbHwFTzP3pZ9P9GHOzlG
kYR+wSECgYEAw/Xida8kSv8n86V3qSY/I+fYQ5V+jDtXIE+JhRnS8xzbOzz3v0WS
Oo5H+o4nJx5eL3Ghb3Gcm0Jn46dHrxinHbm+3RjXv/X6tlbxIYjRSQfHOTSMCTvd
qcliF5vC6RCLXuc7R+IWR1Ky6eDEZGtrvt3DyeYABsp9fRUFR/6NluUCgYEAqNsw
1aSl7WJa27F0DoJdlU9LWerpXcazlJcIdOz/S9QDmSK3RDQTdqfTxRmrxiYI9LEs
mkOkvzlnnOBMpnZ3ZOU5qIRfprecRIi37KDAOHWGnlC0EWGgl46YLb7/jXiWf0AG
Y+DfJJNd9i6TbIDWu8254/erAS6bKMhW/3q7f2kCgYAZ7Id/BiKJAWRpqTRBXlvw
BhXoKvjI2HjYP21z/EyZ+PFPzur/lNaZhIUlMnUfibbwE9pFggQzzf8scM7c7Sf+
mLoVSdoQ/Rujz7CqvQzi2nKSsM7t0curUIb3lJWee5/UeEaxZcmIufoNUrzohAWH
BJOIPDM4ssUTLRq7wYM9uQKBgHCBau5OP8gE6mjKuXsZXWUoahpFLKwwwmJUp2vQ
pOFPJ/6WZOlqkTVT6QPAcPUbTohKrF80hsZqZyDdSfT3peFx4ZLocBrS56m6NmHR
UYHMvJ8rQm76T1fryHVidz85g3zRmfBeWg8yqT5oFg4LYgfLsPm1gRjOhs8LfPvI
OLlRAoGBAIZ5Uv4Z3s8O7WKXXUe/lq6j7vfiVkR1NW/Z/WLKXZpnmvJ7FgxN4e56
RXT7GwNQHIY8eDjDnsHxzrxd+raOxOZeKcMHj3XyjCX3NHfTscnsBPAGYpY/Wxzh
T8UYnFu6RzkixElTf2rseEav7rkdKkI3LAeIZy7B0HulKKsmqVQ7
-----END RSA PRIVATE KEY-----
`
Poem = `Fleas:
Adam
Had'em
E.E. Cummings`
)