hcl/hclwrite/round_trip_test.go

173 lines
3.9 KiB
Go

package hclwrite
import (
"bytes"
"testing"
"github.com/sergi/go-diff/diffmatchpatch"
"github.com/zclconf/go-cty/cty"
"github.com/zclconf/go-cty/cty/function"
"github.com/zclconf/go-cty/cty/function/stdlib"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
)
func TestRoundTripVerbatim(t *testing.T) {
tests := []string{
``,
`foo = 1
`,
`
foobar = 1
baz = 1
`,
`
# this file is awesome
# tossed salads and scrambled eggs
foobar = 1
baz = 1
block {
a = "a"
b = "b"
c = "c"
d = "d"
subblock {
}
subblock {
e = "e"
}
}
# and they all lived happily ever after
`,
}
for _, test := range tests {
t.Run(test, func(t *testing.T) {
src := []byte(test)
file, diags := parse(src, "", hcl.Pos{Line: 1, Column: 1})
if len(diags) != 0 {
for _, diag := range diags {
t.Logf(" - %s", diag.Error())
}
t.Fatalf("unexpected diagnostics")
}
wr := &bytes.Buffer{}
n, err := file.WriteTo(wr)
if n != int64(len(test)) {
t.Errorf("wrong number of bytes %d; want %d", n, len(test))
}
if err != nil {
t.Fatalf("error from WriteTo")
}
result := wr.Bytes()
if !bytes.Equal(result, src) {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(string(src), string(result), false)
//t.Errorf("wrong result\nresult:\n%s\ninput:\n%s", result, src)
t.Errorf("wrong result\ndiff: (red indicates missing lines, and green indicates unexpected lines)\n%s", dmp.DiffPrettyText(diffs))
}
})
}
}
func TestRoundTripFormat(t *testing.T) {
// The goal of this test is to verify that the formatter doesn't change
// the semantics of any expressions when it adds and removes whitespace.
// String templates are the primary area of concern here, but we also
// test some other things for completeness sake.
//
// The tests here must define zero or more attributes, which will be
// extract with JustAttributes and evaluated both before and after
// formatting.
tests := []string{
"",
"\n\n\n",
"a=1\n",
"a=\"hello\"\n",
"a=\"${hello} world\"\n",
"a=upper(\"hello\")\n",
"a=upper(hello)\n",
"a=[1,2,3,4,five]\n",
"a={greeting=hello}\n",
"a={\ngreeting=hello\n}\n",
"a={\ngreeting=hello}\n",
"a={greeting=hello\n}\n",
"a={greeting=hello,number=five,sarcastic=\"${upper(hello)}\"\n}\n",
"a={\ngreeting=hello\nnumber=five\nsarcastic=\"${upper(hello)}\"\n}\n",
"a=<<EOT\nhello\nEOT\n\n",
"a=[<<EOT\nhello\nEOT\n]\n",
"a=[\n<<EOT\nhello\nEOT\n]\n",
"a=[\n]\n",
"a=1\nb=2\nc=3\n",
"a=\"${\n5\n}\"\n",
}
ctx := &hcl.EvalContext{
Variables: map[string]cty.Value{
"hello": cty.StringVal("hello"),
"five": cty.NumberIntVal(5),
},
Functions: map[string]function.Function{
"upper": stdlib.UpperFunc,
},
}
for _, test := range tests {
t.Run(test, func(t *testing.T) {
attrsAsObj := func(src []byte, phase string) cty.Value {
t.Logf("source %s:\n%s", phase, src)
f, diags := hclsyntax.ParseConfig(src, "", hcl.Pos{Line: 1, Column: 1})
if len(diags) != 0 {
for _, diag := range diags {
t.Logf(" - %s", diag.Error())
}
t.Fatalf("unexpected diagnostics in parse %s", phase)
}
attrs, diags := f.Body.JustAttributes()
if len(diags) != 0 {
for _, diag := range diags {
t.Logf(" - %s", diag.Error())
}
t.Fatalf("unexpected diagnostics in JustAttributes %s", phase)
}
vals := map[string]cty.Value{}
for k, attr := range attrs {
val, diags := attr.Expr.Value(ctx)
if len(diags) != 0 {
for _, diag := range diags {
t.Logf(" - %s", diag.Error())
}
t.Fatalf("unexpected diagnostics evaluating %s", phase)
}
vals[k] = val
}
return cty.ObjectVal(vals)
}
src := []byte(test)
before := attrsAsObj(src, "before")
formatted := Format(src)
after := attrsAsObj(formatted, "after")
if !after.RawEquals(before) {
t.Errorf("mismatching after format\nbefore: %#v\nafter: %#v", before, after)
}
})
}
}