OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / hashicorp / hcl / hcl / printer / printer_test.go
1 package printer
2
3 import (
4         "bytes"
5         "errors"
6         "flag"
7         "fmt"
8         "io/ioutil"
9         "path/filepath"
10         "testing"
11
12         "github.com/hashicorp/hcl/hcl/parser"
13 )
14
15 var update = flag.Bool("update", false, "update golden files")
16
17 const (
18         dataDir = "testdata"
19 )
20
21 type entry struct {
22         source, golden string
23 }
24
25 // Use go test -update to create/update the respective golden files.
26 var data = []entry{
27         {"complexhcl.input", "complexhcl.golden"},
28         {"list.input", "list.golden"},
29         {"list_comment.input", "list_comment.golden"},
30         {"comment.input", "comment.golden"},
31         {"comment_crlf.input", "comment.golden"},
32         {"comment_aligned.input", "comment_aligned.golden"},
33         {"comment_array.input", "comment_array.golden"},
34         {"comment_end_file.input", "comment_end_file.golden"},
35         {"comment_multiline_indent.input", "comment_multiline_indent.golden"},
36         {"comment_multiline_no_stanza.input", "comment_multiline_no_stanza.golden"},
37         {"comment_multiline_stanza.input", "comment_multiline_stanza.golden"},
38         {"comment_newline.input", "comment_newline.golden"},
39         {"comment_object_multi.input", "comment_object_multi.golden"},
40         {"comment_standalone.input", "comment_standalone.golden"},
41         {"empty_block.input", "empty_block.golden"},
42         {"list_of_objects.input", "list_of_objects.golden"},
43         {"multiline_string.input", "multiline_string.golden"},
44         {"object_singleline.input", "object_singleline.golden"},
45         {"object_with_heredoc.input", "object_with_heredoc.golden"},
46 }
47
48 func TestFiles(t *testing.T) {
49         for _, e := range data {
50                 source := filepath.Join(dataDir, e.source)
51                 golden := filepath.Join(dataDir, e.golden)
52                 t.Run(e.source, func(t *testing.T) {
53                         check(t, source, golden)
54                 })
55         }
56 }
57
58 func check(t *testing.T, source, golden string) {
59         src, err := ioutil.ReadFile(source)
60         if err != nil {
61                 t.Error(err)
62                 return
63         }
64
65         res, err := format(src)
66         if err != nil {
67                 t.Error(err)
68                 return
69         }
70
71         // update golden files if necessary
72         if *update {
73                 if err := ioutil.WriteFile(golden, res, 0644); err != nil {
74                         t.Error(err)
75                 }
76                 return
77         }
78
79         // get golden
80         gld, err := ioutil.ReadFile(golden)
81         if err != nil {
82                 t.Error(err)
83                 return
84         }
85
86         // formatted source and golden must be the same
87         if err := diff(source, golden, res, gld); err != nil {
88                 t.Error(err)
89                 return
90         }
91 }
92
93 // diff compares a and b.
94 func diff(aname, bname string, a, b []byte) error {
95         var buf bytes.Buffer // holding long error message
96
97         // compare lengths
98         if len(a) != len(b) {
99                 fmt.Fprintf(&buf, "\nlength changed: len(%s) = %d, len(%s) = %d", aname, len(a), bname, len(b))
100         }
101
102         // compare contents
103         line := 1
104         offs := 1
105         for i := 0; i < len(a) && i < len(b); i++ {
106                 ch := a[i]
107                 if ch != b[i] {
108                         fmt.Fprintf(&buf, "\n%s:%d:%d: %q", aname, line, i-offs+1, lineAt(a, offs))
109                         fmt.Fprintf(&buf, "\n%s:%d:%d: %q", bname, line, i-offs+1, lineAt(b, offs))
110                         fmt.Fprintf(&buf, "\n\n")
111                         break
112                 }
113                 if ch == '\n' {
114                         line++
115                         offs = i + 1
116                 }
117         }
118
119         if buf.Len() > 0 {
120                 return errors.New(buf.String())
121         }
122         return nil
123 }
124
125 // format parses src, prints the corresponding AST, verifies the resulting
126 // src is syntactically correct, and returns the resulting src or an error
127 // if any.
128 func format(src []byte) ([]byte, error) {
129         formatted, err := Format(src)
130         if err != nil {
131                 return nil, err
132         }
133
134         // make sure formatted output is syntactically correct
135         if _, err := parser.Parse(formatted); err != nil {
136                 return nil, fmt.Errorf("parse: %s\n%s", err, formatted)
137         }
138
139         return formatted, nil
140 }
141
142 // lineAt returns the line in text starting at offset offs.
143 func lineAt(text []byte, offs int) []byte {
144         i := offs
145         for i < len(text) && text[i] != '\n' {
146                 i++
147         }
148         return text[offs:i]
149 }