From 0fc42b65dfd68c066a23d557f54d59074f4045c0 Mon Sep 17 00:00:00 2001 From: Fatih Arslan Date: Sun, 25 Oct 2015 17:51:18 +0300 Subject: [PATCH] printer: implement file tests --- printer/nodes.go | 20 ++-- printer/printer_test.go | 168 ++++++++++++++++++++--------- printer/testdata/complexhcl.golden | 39 +++++++ printer/testdata/complexhcl.input | 42 ++++++++ 4 files changed, 205 insertions(+), 64 deletions(-) create mode 100644 printer/testdata/complexhcl.golden create mode 100644 printer/testdata/complexhcl.input diff --git a/printer/nodes.go b/printer/nodes.go index 0b97346..f338250 100644 --- a/printer/nodes.go +++ b/printer/nodes.go @@ -111,18 +111,14 @@ func writeBlank(buf io.ByteWriter, indent int) { } func indent(buf []byte) []byte { - splitted := bytes.Split(buf, []byte{newline}) - newBuf := make([]byte, len(splitted)) - for i, s := range splitted { - s = append(s, 0) - copy(s[1:], s[0:]) - s[0] = tab - newBuf = append(newBuf, s...) - - if i != len(splitted)-1 { - newBuf = append(newBuf, newline) + var res []byte + bol := true + for _, c := range buf { + if bol && c != '\n' { + res = append(res, []byte{tab}...) } + res = append(res, c) + bol = c == '\n' } - - return newBuf + return res } diff --git a/printer/printer_test.go b/printer/printer_test.go index e7bf891..1141e85 100644 --- a/printer/printer_test.go +++ b/printer/printer_test.go @@ -1,73 +1,137 @@ package printer import ( + "bytes" + "errors" + "flag" "fmt" - "os" + "io/ioutil" + "path/filepath" "testing" "github.com/fatih/hcl/parser" ) -var listHCL = `foo = ["fatih", "arslan"]` -var listHCL2 = `foo = [ - "fatih", - "arslan", -]` +var update = flag.Bool("update", false, "update golden files") -var complexHcl = `// This comes from Terraform, as a test -variable "foo" { - default = "bar" - description = "bar" +const ( + dataDir = "testdata" +) + +type entry struct { + source, golden string } -provider "aws" { - access_key = "foo" - secret_key = "bar" +// Use go test -update to create/update the respective golden files. +var data = []entry{ + {"complexhcl.input", "complexhcl.golden"}, } -provider "do" { - api_key = "${var.foo}" +func TestFiles(t *testing.T) { + for _, e := range data { + source := filepath.Join(dataDir, e.source) + golden := filepath.Join(dataDir, e.golden) + check(t, source, golden) + } } -resource "aws_security_group" "firewall" { - count = 5 -} - -resource aws_instance "web" { - ami = "${var.foo}" - security_groups = [ - "foo", - "${aws_security_group.firewall.foo}" - ] - - network_interface { - device_index = 0 - description = "Main network interface" - } -} - -resource "aws_instance" "db" { - security_groups = "${aws_security_group.firewall.*.id}" - VPC = "foo" - - depends_on = ["aws_instance.web"] -} - -output "web_ip" { - value = "${aws_instance.web.private_ip}" -} -` - -func TestPrint(t *testing.T) { - node, err := parser.Parse([]byte(complexHcl)) - // node, err := parser.Parse([]byte(listHCL2)) +func check(t *testing.T, source, golden string) { + src, err := ioutil.ReadFile(source) if err != nil { - t.Fatal(err) - } - - if err := Fprint(os.Stdout, node); err != nil { t.Error(err) + return } - fmt.Println("") + res, err := format(src) + if err != nil { + t.Error(err) + return + } + + // update golden files if necessary + if *update { + if err := ioutil.WriteFile(golden, res, 0644); err != nil { + t.Error(err) + } + return + } + + // get golden + gld, err := ioutil.ReadFile(golden) + if err != nil { + t.Error(err) + return + } + + // formatted source and golden must be the same + if err := diff(source, golden, res, gld); err != nil { + t.Error(err) + return + } +} + +// diff compares a and b. +func diff(aname, bname string, a, b []byte) error { + var buf bytes.Buffer // holding long error message + + // compare lengths + if len(a) != len(b) { + fmt.Fprintf(&buf, "\nlength changed: len(%s) = %d, len(%s) = %d", aname, len(a), bname, len(b)) + } + + // compare contents + line := 1 + offs := 1 + for i := 0; i < len(a) && i < len(b); i++ { + ch := a[i] + if ch != b[i] { + fmt.Fprintf(&buf, "\n%s:%d:%d: %s", aname, line, i-offs+1, lineAt(a, offs)) + fmt.Fprintf(&buf, "\n%s:%d:%d: %s", bname, line, i-offs+1, lineAt(b, offs)) + fmt.Fprintf(&buf, "\n\n") + break + } + if ch == '\n' { + line++ + offs = i + 1 + } + } + + if buf.Len() > 0 { + return errors.New(buf.String()) + } + return nil +} + +// format parses src, prints the corresponding AST, verifies the resulting +// src is syntactically correct, and returns the resulting src or an error +// if any. +func format(src []byte) ([]byte, error) { + // parse src + node, err := parser.Parse(src) + if err != nil { + return nil, fmt.Errorf("parse: %s\n%s", err, src) + } + + var buf bytes.Buffer + if err := Fprint(&buf, node); err != nil { + return nil, fmt.Errorf("print: %s", err) + } + + // make sure formatted output is syntactically correct + res := buf.Bytes() + + if _, err := parser.Parse(src); err != nil { + return nil, fmt.Errorf("parse: %s\n%s", err, src) + } + + return res, nil +} + +// lineAt returns the line in text starting at offset offs. +func lineAt(text []byte, offs int) []byte { + i := offs + for i < len(text) && text[i] != '\n' { + i++ + } + return text[offs:i] } diff --git a/printer/testdata/complexhcl.golden b/printer/testdata/complexhcl.golden new file mode 100644 index 0000000..10ab6d3 --- /dev/null +++ b/printer/testdata/complexhcl.golden @@ -0,0 +1,39 @@ +variable "foo" = { + default = "bar" + description = "bar" +} + +provider "aws" = { + access_key = "foo" + secret_key = "bar" +} + +provider "do" = { + api_key = "${var.foo}" +} + +resource "aws_security_group" "firewall" = { + count = 5 +} + +resource aws_instance "web" = { + ami = "${var.foo}" + security_groups = [ + "foo", + "${aws_security_group.firewall.foo}", + ] + network_interface = { + device_index = 0 + description = "Main network interface" + } +} + +resource "aws_instance" "db" = { + security_groups = "${aws_security_group.firewall.*.id}" + VPC = "foo" + depends_on = [ "aws_instance.web"] +} + +output "web_ip" = { + value = "${aws_instance.web.private_ip}" +} diff --git a/printer/testdata/complexhcl.input b/printer/testdata/complexhcl.input new file mode 100644 index 0000000..cccb5b0 --- /dev/null +++ b/printer/testdata/complexhcl.input @@ -0,0 +1,42 @@ +// This comes from Terraform, as a test +variable "foo" { + default = "bar" + description = "bar" +} + +provider "aws" { + access_key = "foo" + secret_key = "bar" +} + +provider "do" { + api_key = "${var.foo}" +} + +resource "aws_security_group" "firewall" { + count = 5 +} + +resource aws_instance "web" { + ami = "${var.foo}" + security_groups = [ + "foo", + "${aws_security_group.firewall.foo}" + ] + + network_interface { + device_index = 0 + description = "Main network interface" + } +} + +resource "aws_instance" "db" { + security_groups = "${aws_security_group.firewall.*.id}" + VPC = "foo" + + depends_on = ["aws_instance.web"] +} + +output "web_ip" { + value = "${aws_instance.web.private_ip}" +}