2018-11-12 15:42:24 +00:00
|
|
|
package nginx
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2018-11-13 20:11:15 +00:00
|
|
|
"errors"
|
2018-11-12 15:42:24 +00:00
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestDecodeEncode(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
Input string
|
|
|
|
Output string
|
|
|
|
}{
|
2018-11-12 21:54:37 +00:00
|
|
|
{"key\t\tvalue;\n", "key\t\tvalue;\n"},
|
|
|
|
{"key value;\n", "key\t\tvalue;\n"},
|
|
|
|
{"key value;\n", "key\t\tvalue;\n"},
|
|
|
|
{"key \t value;\n", "key\t\tvalue;\n"},
|
|
|
|
{"key\tvalue;\n", "key\t\tvalue;\n"},
|
|
|
|
{"ke-y value;\n", "ke-y\t\tvalue;\n"},
|
|
|
|
{"ke_y value;\n", "ke_y\t\tvalue;\n"},
|
|
|
|
{"key value; \n", "key\t\tvalue;\n"},
|
|
|
|
{"key value;\t\n", "key\t\tvalue;\n"},
|
|
|
|
{"\tkey value;\n", "key\t\tvalue;\n"},
|
|
|
|
{" \t key value;\n", "key\t\tvalue;\n"},
|
2018-11-12 15:42:24 +00:00
|
|
|
|
|
|
|
{"include ./file/*.conf;\n", "include ./file/*.conf;\n"},
|
|
|
|
{"include ./file/*.conf; \n", "include ./file/*.conf;\n"},
|
|
|
|
{"include ./file/*.conf;\t\n", "include ./file/*.conf;\n"},
|
|
|
|
{"\tinclude ./file/*.conf;\n", "include ./file/*.conf;\n"},
|
|
|
|
{" \t include ./file/*.conf;\n", "include ./file/*.conf;\n"},
|
|
|
|
|
|
|
|
{"sectionname {\n}\n", "sectionname {\n}\n\n"},
|
|
|
|
{"section-name {\n}\n", "section-name {\n}\n\n"},
|
|
|
|
{"section_name {\n}\n", "section_name {\n}\n\n"},
|
|
|
|
{"sectionname { \n}\n", "sectionname {\n}\n\n"},
|
|
|
|
{"sectionname {\t\n}\n", "sectionname {\n}\n\n"},
|
|
|
|
{"\tsectionname {\n}\n", "sectionname {\n}\n\n"},
|
|
|
|
{" \t sectionname {\n}\n", "sectionname {\n}\n\n"},
|
2018-11-12 16:07:30 +00:00
|
|
|
{"sectionname ~ with-args {\t\n}\n", "sectionname ~ with-args {\n}\n\n"},
|
2018-11-12 15:42:24 +00:00
|
|
|
|
|
|
|
{"#some comment\n", "#some comment\n"},
|
|
|
|
{"#some\tcomment\n", "#some\tcomment\n"},
|
|
|
|
{"# some comment \n", "# some comment\n"},
|
|
|
|
{"# some comment \t\n", "# some comment\n"},
|
|
|
|
{"\t# some comment {\n", "# some comment {\n"},
|
|
|
|
|
|
|
|
{";some comment\n", ";some comment\n"},
|
|
|
|
{"; some\tcomment\n", "; some\tcomment\n"},
|
|
|
|
{"; some comment\n", "; some comment\n"},
|
|
|
|
{"; some comment \n", "; some comment\n"},
|
|
|
|
{"; some comment \t\n", "; some comment\n"},
|
|
|
|
{"\t; some comment {\n", "; some comment {\n"},
|
2018-11-12 15:50:50 +00:00
|
|
|
|
|
|
|
{"a{\n}\n", "a {\n}\n\n"},
|
|
|
|
{"a{\n\n}\n", "a {\n}\n\n"},
|
|
|
|
{"a{\n; some comment\n}\n", "a {\n\t; some comment\n}\n\n"},
|
|
|
|
{"a{\n; some comment\n #another comment\n}\n", "a {\n\t; some comment\n\t#another comment\n}\n\n"},
|
|
|
|
{"a{\nb{\n}\n}\n", "a {\n\tb {\n\t}\n\n}\n\n"},
|
|
|
|
{"a{\n\tb{\n\t}\n}\n", "a {\n\tb {\n\t}\n\n}\n\n"},
|
|
|
|
{"a{\nb{\nc{\n}\n}\n}\n", "a {\n\tb {\n\t\tc {\n\t\t}\n\n\t}\n\n}\n\n"},
|
2018-11-12 15:42:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for i, test := range tests {
|
|
|
|
|
|
|
|
// create reader/writer
|
|
|
|
r, w := strings.NewReader(test.Input), &bytes.Buffer{}
|
|
|
|
|
|
|
|
// parse input
|
2018-11-12 18:22:24 +00:00
|
|
|
receiver := new(Line)
|
2018-11-12 15:42:24 +00:00
|
|
|
decoder := NewDecoder(r)
|
|
|
|
if err := decoder.Decode(receiver); err != nil {
|
|
|
|
t.Errorf("[%d] unexpected error <%s>", i, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// encode back to writer
|
|
|
|
encoder := NewEncoder(w)
|
|
|
|
encoder.SetIndent("", "\t")
|
|
|
|
if err := encoder.Encode(receiver); err != nil {
|
|
|
|
t.Errorf("[%d] unexpected error <%s>", i, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// check equality
|
|
|
|
if w.String() != test.Output {
|
2018-11-12 16:07:30 +00:00
|
|
|
t.Errorf("[%d] expected '%s', got '%s'", i, escape(test.Output), escape(w.String()))
|
2018-11-12 15:42:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-13 19:58:19 +00:00
|
|
|
func TestErrors(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
Receiver interface{}
|
|
|
|
Input string
|
|
|
|
Err error
|
|
|
|
}{
|
|
|
|
{new(Line), "", nil},
|
|
|
|
{nil, "", ErrInvalidReceiver},
|
|
|
|
{[]byte{}, "", ErrInvalidReceiver},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, test := range tests {
|
|
|
|
|
|
|
|
// create reader/writer
|
|
|
|
r, w := strings.NewReader(test.Input), &bytes.Buffer{}
|
|
|
|
|
|
|
|
// parse input
|
|
|
|
var receiver interface{} = new(Line)
|
|
|
|
decoder := NewDecoder(r)
|
|
|
|
if err := decoder.Decode(receiver); err != nil {
|
|
|
|
t.Errorf("[%d] unexpected error <%s>", i, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// encode back to writer
|
|
|
|
receiver = test.Receiver
|
|
|
|
encoder := NewEncoder(w)
|
|
|
|
encoder.SetIndent("", "\t")
|
|
|
|
if err := encoder.Encode(receiver); err != test.Err {
|
|
|
|
t.Errorf("[%d] expected error <%s>, got <%s>", i, test.Err, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDefaultIndent(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
|
|
Input string
|
|
|
|
SetIndent []string
|
|
|
|
Output string
|
|
|
|
}{
|
|
|
|
{"section {\nkey value;\n}\n", []string{"*prefix*", "*indent*"}, "*prefix*section {\n*prefix**indent*key\t\tvalue;\n*prefix*}\n\n"},
|
|
|
|
{"section {\nkey value;\n}\n", nil, "section {\n\tkey\t\tvalue;\n}\n\n"},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, test := range tests {
|
|
|
|
|
|
|
|
// create reader/writer
|
|
|
|
r, w := strings.NewReader(test.Input), &bytes.Buffer{}
|
|
|
|
|
|
|
|
// parse input
|
|
|
|
receiver := new(Line)
|
|
|
|
decoder := NewDecoder(r)
|
|
|
|
if err := decoder.Decode(receiver); err != nil {
|
|
|
|
t.Errorf("[%d] unexpected error <%s>", i, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// encode back to writer
|
|
|
|
encoder := NewEncoder(w)
|
|
|
|
if test.SetIndent != nil && len(test.SetIndent) >= 2 {
|
|
|
|
encoder.SetIndent(test.SetIndent[0], test.SetIndent[1])
|
|
|
|
}
|
|
|
|
if err := encoder.Encode(receiver); err != nil {
|
|
|
|
t.Errorf("[%d] unexpected error <%s>", i, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// check equality
|
|
|
|
if w.String() != test.Output {
|
|
|
|
t.Errorf("[%d] expected '%s', got '%s'", i, escape(test.Output), escape(w.String()))
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-13 20:11:15 +00:00
|
|
|
var writerError = errors.New("error")
|
|
|
|
|
|
|
|
type defectiveWriter struct{}
|
|
|
|
|
|
|
|
func (d defectiveWriter) Write(buf []byte) (int, error) {
|
|
|
|
return 0, writerError
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWriteError(t *testing.T) {
|
|
|
|
|
|
|
|
input := "section {\nkey value;\n}\n"
|
|
|
|
|
|
|
|
// create reader/writer
|
|
|
|
r, w := strings.NewReader(input), &defectiveWriter{}
|
|
|
|
|
|
|
|
// parse input
|
|
|
|
receiver := new(Line)
|
|
|
|
decoder := NewDecoder(r)
|
|
|
|
if err := decoder.Decode(receiver); err != nil {
|
|
|
|
t.Fatalf("unexpected error <%s>", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// encode back to writer
|
|
|
|
encoder := NewEncoder(w)
|
|
|
|
if err := encoder.Encode(receiver); err != writerError {
|
|
|
|
t.Fatalf("expected error <%s>, got <%s>", writerError, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-11-12 15:42:24 +00:00
|
|
|
func escape(raw string) string {
|
|
|
|
|
|
|
|
escaped := make([]rune, 0)
|
|
|
|
|
|
|
|
for _, char := range raw {
|
|
|
|
if char == '\n' {
|
|
|
|
escaped = append(escaped, []rune("\\n")...)
|
|
|
|
} else if char == '\t' {
|
|
|
|
escaped = append(escaped, []rune("\\t")...)
|
|
|
|
} else if char == '\r' {
|
|
|
|
escaped = append(escaped, []rune("\\r")...)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
escaped = append(escaped, char)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(escaped)
|
|
|
|
|
|
|
|
}
|