blob: 4a152adc0e7cc23440949885c7d01cfc69ab4b63 [file] [log] [blame]
// +build !windows
// TODO(jen20): These need fixing on Windows but fmt is not used right now
// and red CI is making it harder to process other bugs, so ignore until
// we get around to fixing them.
package fmtcmd
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"regexp"
"sort"
"syscall"
"testing"
"google3/third_party/golang/hashicorp/hcl/testhelper/testhelper"
)
var fixtureExtensions = []string{"hcl"}
func init() {
sort.Sort(ByFilename(fixtures))
}
func TestIsValidFile(t *testing.T) {
const fixtureDir = "./test-fixtures"
cases := []struct {
Path string
Expected bool
}{
{"good.hcl", true},
{".hidden.ignore", false},
{"file.ignore", false},
{"dir.ignore", false},
}
for _, tc := range cases {
file, err := os.Stat(filepath.Join(fixtureDir, tc.Path))
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if res := isValidFile(file, fixtureExtensions); res != tc.Expected {
t.Errorf("want: %t, got: %t", tc.Expected, res)
}
}
}
func TestRunMultiplePaths(t *testing.T) {
path1, err := renderFixtures("")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
defer os.RemoveAll(path1)
path2, err := renderFixtures("")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
defer os.RemoveAll(path2)
var expectedOut bytes.Buffer
for _, path := range []string{path1, path2} {
for _, fixture := range fixtures {
if !bytes.Equal(fixture.golden, fixture.input) {
expectedOut.WriteString(filepath.Join(path, fixture.filename) + "\n")
}
}
}
_, stdout := mockIO()
err = Run(
[]string{path1, path2},
fixtureExtensions,
nil, stdout,
Options{
List: true,
},
)
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if stdout.String() != expectedOut.String() {
t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut.String(), stdout.String())
}
}
func TestRunSubDirectories(t *testing.T) {
pathParent, err := ioutil.TempDir("", "")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
defer os.RemoveAll(pathParent)
path1, err := renderFixtures(pathParent)
if err != nil {
t.Errorf("unexpected error: %s", err)
}
path2, err := renderFixtures(pathParent)
if err != nil {
t.Errorf("unexpected error: %s", err)
}
paths := []string{path1, path2}
sort.Strings(paths)
var expectedOut bytes.Buffer
for _, path := range paths {
for _, fixture := range fixtures {
if !bytes.Equal(fixture.golden, fixture.input) {
expectedOut.WriteString(filepath.Join(path, fixture.filename) + "\n")
}
}
}
_, stdout := mockIO()
err = Run(
[]string{pathParent},
fixtureExtensions,
nil, stdout,
Options{
List: true,
},
)
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if stdout.String() != expectedOut.String() {
t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut.String(), stdout.String())
}
}
func TestRunStdin(t *testing.T) {
var expectedOut bytes.Buffer
for i, fixture := range fixtures {
if i != 0 {
expectedOut.WriteString("\n")
}
expectedOut.Write(fixture.golden)
}
stdin, stdout := mockIO()
for _, fixture := range fixtures {
stdin.Write(fixture.input)
}
err := Run(
[]string{},
fixtureExtensions,
stdin, stdout,
Options{},
)
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if !bytes.Equal(stdout.Bytes(), expectedOut.Bytes()) {
t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut.String(), stdout.String())
}
}
func TestRunStdinAndWrite(t *testing.T) {
var expectedOut = []byte{}
stdin, stdout := mockIO()
stdin.WriteString("")
err := Run(
[]string{}, []string{},
stdin, stdout,
Options{
Write: true,
},
)
if err != ErrWriteStdin {
t.Errorf("error want:\n%s\ngot:\n%s", ErrWriteStdin, err)
}
if !bytes.Equal(stdout.Bytes(), expectedOut) {
t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut, stdout)
}
}
func TestRunFileError(t *testing.T) {
path, err := ioutil.TempDir("", "")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
defer os.RemoveAll(path)
filename := filepath.Join(path, "unreadable.hcl")
var expectedError = &os.PathError{
Op: "open",
Path: filename,
Err: syscall.EACCES,
}
err = ioutil.WriteFile(filename, []byte{}, 0000)
if err != nil {
t.Errorf("unexpected error: %s", err)
}
_, stdout := mockIO()
err = Run(
[]string{path},
fixtureExtensions,
nil, stdout,
Options{},
)
if !reflect.DeepEqual(err, expectedError) {
t.Errorf("error want: %#v, got: %#v", expectedError, err)
}
}
func TestRunNoOptions(t *testing.T) {
path, err := renderFixtures("")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
defer os.RemoveAll(path)
var expectedOut bytes.Buffer
for _, fixture := range fixtures {
expectedOut.Write(fixture.golden)
}
_, stdout := mockIO()
err = Run(
[]string{path},
fixtureExtensions,
nil, stdout,
Options{},
)
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if stdout.String() != expectedOut.String() {
t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut.String(), stdout.String())
}
}
func TestRunList(t *testing.T) {
path, err := renderFixtures("")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
defer os.RemoveAll(path)
var expectedOut bytes.Buffer
for _, fixture := range fixtures {
if !bytes.Equal(fixture.golden, fixture.input) {
expectedOut.WriteString(fmt.Sprintln(filepath.Join(path, fixture.filename)))
}
}
_, stdout := mockIO()
err = Run(
[]string{path},
fixtureExtensions,
nil, stdout,
Options{
List: true,
},
)
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if stdout.String() != expectedOut.String() {
t.Errorf("stdout want:\n%s\ngot:\n%s", expectedOut.String(), stdout.String())
}
}
func TestRunWrite(t *testing.T) {
path, err := renderFixtures("")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
defer os.RemoveAll(path)
_, stdout := mockIO()
err = Run(
[]string{path},
fixtureExtensions,
nil, stdout,
Options{
Write: true,
},
)
if err != nil {
t.Errorf("unexpected error: %s", err)
}
for _, fixture := range fixtures {
res, err := ioutil.ReadFile(filepath.Join(path, fixture.filename))
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if !bytes.Equal(res, fixture.golden) {
t.Errorf("file %q contents want:\n%s\ngot:\n%s", fixture.filename, fixture.golden, res)
}
}
}
func TestRunDiff(t *testing.T) {
path, err := renderFixtures("")
if err != nil {
t.Errorf("unexpected error: %s", err)
}
defer os.RemoveAll(path)
var expectedOut bytes.Buffer
for _, fixture := range fixtures {
if len(fixture.diff) > 0 {
expectedOut.WriteString(
regexp.QuoteMeta(
fmt.Sprintf("diff a/%s/%s b/%s/%s\n", path, fixture.filename, path, fixture.filename),
),
)
// Need to use regex to ignore datetimes in diff.
expectedOut.WriteString(`--- .+?\n`)
expectedOut.WriteString(`\+\+\+ .+?\n`)
expectedOut.WriteString(regexp.QuoteMeta(string(fixture.diff)))
}
}
expectedOutString := testhelper.Unix2dos(expectedOut.String())
_, stdout := mockIO()
err = Run(
[]string{path},
fixtureExtensions,
nil, stdout,
Options{
Diff: true,
},
)
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if !regexp.MustCompile(expectedOutString).Match(stdout.Bytes()) {
t.Errorf("stdout want match:\n%s\ngot:\n%q", expectedOutString, stdout)
}
}
func mockIO() (stdin, stdout *bytes.Buffer) {
return new(bytes.Buffer), new(bytes.Buffer)
}
type fixture struct {
filename string
input, golden, diff []byte
}
type ByFilename []fixture
func (s ByFilename) Len() int { return len(s) }
func (s ByFilename) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s ByFilename) Less(i, j int) bool { return len(s[i].filename) > len(s[j].filename) }
var fixtures = []fixture{
{
"noop.hcl",
[]byte(`resource "aws_security_group" "firewall" {
count = 5
}
`),
[]byte(`resource "aws_security_group" "firewall" {
count = 5
}
`),
[]byte(``),
}, {
"align_equals.hcl",
[]byte(`variable "foo" {
default = "bar"
description = "bar"
}
`),
[]byte(`variable "foo" {
default = "bar"
description = "bar"
}
`),
[]byte(`@@ -1,4 +1,4 @@
variable "foo" {
- default = "bar"
+ default = "bar"
description = "bar"
}
`),
}, {
"indentation.hcl",
[]byte(`provider "aws" {
access_key = "foo"
secret_key = "bar"
}
`),
[]byte(`provider "aws" {
access_key = "foo"
secret_key = "bar"
}
`),
[]byte(`@@ -1,4 +1,4 @@
provider "aws" {
- access_key = "foo"
- secret_key = "bar"
+ access_key = "foo"
+ secret_key = "bar"
}
`),
},
}
// parent can be an empty string, in which case the system's default
// temporary directory will be used.
func renderFixtures(parent string) (path string, err error) {
path, err = ioutil.TempDir(parent, "")
if err != nil {
return "", err
}
for _, fixture := range fixtures {
err = ioutil.WriteFile(filepath.Join(path, fixture.filename), []byte(fixture.input), 0644)
if err != nil {
os.RemoveAll(path)
return "", err
}
}
return path, nil
}