1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
|
package main_test
import (
"bytes"
"io"
"io/ioutil"
"os"
"reflect"
"testing"
"time"
main "github.com/benbjohnson/tmpl"
)
// Ensure paths can be parsed from command line flags.
func TestMain_ParseFlags_Paths(t *testing.T) {
m := NewMain()
if err := m.ParseFlags([]string{"a", "b", "c"}); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(m.Paths, []string{"a", "b", "c"}) {
t.Fatalf("unexpected paths: %+v", m.Paths)
}
}
// Ensure data can be parsed from command line flags as JSON.
func TestMain_ParseFlags_Data_JSON(t *testing.T) {
m := NewMain()
if err := m.ParseFlags([]string{"-data", `{"foo":"bar"}`}); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(m.Data, map[string]interface{}{"foo": "bar"}) {
t.Fatalf("unexpected data: %#v", m.Data)
}
}
// Ensure data can be parsed from command line flags as a filename.
func TestMain_ParseFlags_Data_File(t *testing.T) {
m := NewMain()
m.FileReadWriter.ReadFileFn = func(filename string) ([]byte, error) {
if filename != "path/to/data" {
t.Fatalf("unexpected filename: %s", filename)
}
return []byte(`{"foo":"bar"}`), nil
}
if err := m.ParseFlags([]string{"-data", `@path/to/data`}); err != nil {
t.Fatal(err)
} else if !reflect.DeepEqual(m.Data, map[string]interface{}{"foo": "bar"}) {
t.Fatalf("unexpected data: %#v", m.Data)
}
}
// Ensure a basic template file can be processed.
func TestMain_Run(t *testing.T) {
m := NewMain()
m.OS.StatFn = func(filename string) (os.FileInfo, error) {
if filename != "a.tmpl" {
t.Fatalf("unexpected filename: %s", filename)
}
return &fileInfo{mode: 0666}, nil
}
m.FileReadWriter.ReadFileFn = func(filename string) ([]byte, error) {
if filename != "a.tmpl" {
t.Fatalf("unexpected filename: %s", filename)
}
return []byte(`hi {{.name}}, you are {{.age}}`), nil
}
m.FileReadWriter.WriteFileFn = func(filename string, data []byte, perm os.FileMode) error {
if filename != "a" {
t.Fatalf("unexpected filename: %s", filename)
} else if string(data) != `hi bob, you are 12` {
t.Fatalf("unexpected data: %s", data)
} else if perm != 0666 {
t.Fatalf("unexpected perm: %s", perm)
}
return nil
}
m.Paths = []string{"a.tmpl"}
m.Data = map[string]interface{}{"name": "bob", "age": 12}
if err := m.Run(); err != nil {
t.Fatal(err)
}
}
// Ensure a file can be processed against array data.
func TestMain_Run_Array(t *testing.T) {
m := NewMain()
m.FileReadWriter.ReadFileFn = func(filename string) ([]byte, error) {
return []byte(`I like{{range .}} ({{.}}){{end}}`), nil
}
m.FileReadWriter.WriteFileFn = func(filename string, data []byte, perm os.FileMode) error {
if string(data) != `I like (apple) (pear)` {
t.Fatalf("unexpected data: %s", data)
}
return nil
}
m.Paths = []string{"a.tmpl"}
m.Data = []interface{}{"apple", "pear"}
if err := m.Run(); err != nil {
t.Fatal(err)
}
}
// Ensure a file will add a comment header if generating a Go file.
func TestMain_Run_Header_Go(t *testing.T) {
m := NewMain()
m.FileReadWriter.ReadFileFn = func(filename string) ([]byte, error) {
return []byte("\n\n\n\n\n\npackage foo"), nil
}
m.FileReadWriter.WriteFileFn = func(filename string, data []byte, perm os.FileMode) error {
if string(data) != "// Generated by tmpl\n// https://github.com/benbjohnson/tmpl\n//\n// DO NOT EDIT!\n// Source: x.go.tmpl\n\npackage foo\n" {
t.Fatalf("unexpected data: %s", data)
}
return nil
}
m.Paths = []string{"x.go.tmpl"}
m.Data = []interface{}{"apple", "pear"}
if err := m.Run(); err != nil {
t.Fatal(err)
}
}
// Main is a test wrapper for main.Main.
type Main struct {
*main.Main
OS MainOS
FileReadWriter MainFileReadWriter
Stdin bytes.Buffer
Stdout bytes.Buffer
Stderr bytes.Buffer
}
// NewMain returns a new instance of Main.
// If the verbose command line flag is set then stdout/stderr also go to the terminal.
func NewMain() *Main {
m := &Main{Main: main.NewMain()}
m.Main.OS = &m.OS
m.Main.FileReadWriter = &m.FileReadWriter
m.Main.Stdin = &m.Stdin
m.Main.Stdout = &m.Stdout
m.Main.Stderr = &m.Stderr
if testing.Verbose() {
m.Main.Stdout = io.MultiWriter(os.Stdout, m.Main.Stdout)
m.Main.Stderr = io.MultiWriter(os.Stderr, m.Main.Stderr)
}
// Default stat() to use 0666.
m.OS.StatFn = DefaultOSStat
return m
}
// MainOS is a mockable implementation of Main.OS.
type MainOS struct {
StatFn func(filename string) (os.FileInfo, error)
}
func (os *MainOS) Stat(filename string) (os.FileInfo, error) {
return os.StatFn(filename)
}
func DefaultOSStat(filename string) (os.FileInfo, error) { return &fileInfo{mode: 0666}, nil }
// MainFileReadWriter is a mockable implementation of Main.FileReadWriter.
type MainFileReadWriter struct {
ReadFileFn func(filename string) ([]byte, error)
WriteFileFn func(filename string, data []byte, perm os.FileMode) error
}
func (r *MainFileReadWriter) ReadFile(filename string) ([]byte, error) {
return r.ReadFileFn(filename)
}
func (r *MainFileReadWriter) WriteFile(filename string, data []byte, perm os.FileMode) error {
return r.WriteFileFn(filename, data, perm)
}
type fileInfo struct {
mode os.FileMode
}
func (fi *fileInfo) Name() string { return "" }
func (fi *fileInfo) Size() int64 { return 0 }
func (fi *fileInfo) Mode() os.FileMode { return fi.mode }
func (fi *fileInfo) ModTime() time.Time { return time.Time{} }
func (fi *fileInfo) IsDir() bool { return false }
func (fi *fileInfo) Sys() interface{} { return nil }
// MustTempDir returns a temporary directory. Panic on error.
func MustTempDir() string {
path, err := ioutil.TempDir("", "tmpl-")
if err != nil {
panic(err)
}
return path
}
// MustRemoveAll recursively removes a path. Panic on error.
func MustRemoveAll(path string) {
if err := os.RemoveAll(path); err != nil {
panic(err)
}
}
// MustWriteFile writes data to filename. Panic on error.
func MustWriteFile(filename string, data []byte, perm os.FileMode) {
if err := ioutil.WriteFile(filename, data, perm); err != nil {
panic(err)
}
}
// MustReadFile reads all data from filename. Panic on error.
func MustReadFile(filename string) []byte {
data, err := ioutil.ReadFile(filename)
if err != nil {
panic(err)
}
return data
}
|