package nginx import ( "bytes" "errors" "strings" "testing" ) func TestDecodeEncode(t *testing.T) { tests := []struct { Input string Output string }{ {"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"}, {"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"}, {"sectionname ~ with-args {\t\n}\n", "sectionname ~ with-args {\n}\n\n"}, {"#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"}, {"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"}, } 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) 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 { t.Errorf("[%d] expected '%s', got '%s'", i, escape(test.Output), escape(w.String())) } } } 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())) } } } var errWriter = errors.New("error") type defectiveWriter struct{} func (d defectiveWriter) Write(buf []byte) (int, error) { return 0, errWriter } 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 != errWriter { t.Fatalf("expected error <%s>, got <%s>", errWriter, err) } } 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) }