feature: result formatter extensibility with minor refactor and several testsy

pull/58/head
Salahutdinov Dmitry 7 years ago
parent e965e65506
commit e6e364370d

@ -11,6 +11,7 @@ env:
script:
- test -z "$(gofmt -l ./)"
- test -z "$(go vet -v ./...)"
- go test ./...
- go build
# after_success:
# # Publish as pre-release if it isn't a pull request

@ -11,6 +11,11 @@ import (
"github.com/mitchellh/go-homedir"
)
var ContentTypes = map[string]string{
"json": "application/json",
"form": "application/x-www-form-urlencoded",
}
// Duration is used to automatically unmarshal timeout strings to
// time.Duration values
type Duration struct {

@ -0,0 +1,23 @@
package formatter
import (
"encoding/hex"
"fmt"
"io"
)
type binaryFormatter struct {
}
func (f *binaryFormatter) Format(writer io.Writer, data []byte) error {
fmt.Fprint(writer, hex.Dump(data))
return nil
}
func (f *binaryFormatter) Title() string {
return "[binary]"
}
func (f *binaryFormatter) Searchable() bool {
return false
}

@ -0,0 +1,28 @@
package formatter
import (
"io"
"mime"
"strings"
"github.com/asciimoo/wuzz/config"
)
type ResponseFormatter interface {
Format(writer io.Writer, data []byte) error
Title() string
Searchable() bool
}
func New(appConfig *config.Config, contentType string) ResponseFormatter {
ctype, _, err := mime.ParseMediaType(contentType)
if err == nil && appConfig.General.FormatJSON && (ctype == config.ContentTypes["json"] || strings.HasSuffix(ctype, "+json")) {
return &jsonFormatter{}
} else if strings.Contains(contentType, "text/html") {
return &htmlFormatter{}
} else if strings.Index(contentType, "text") == -1 && strings.Index(contentType, "application") == -1 {
return &binaryFormatter{}
} else {
return &textFormatter{}
}
}

@ -0,0 +1,97 @@
package formatter
import (
"bytes"
"testing"
"github.com/asciimoo/wuzz/config"
"github.com/nwidger/jsoncolor"
)
func TestFormat(t *testing.T) {
var binBuffer bytes.Buffer
New(configFixture(true), "octet-stream").Format(&binBuffer, []byte("some binary data"))
if binBuffer.String() != "00000000 73 6f 6d 65 20 62 69 6e 61 72 79 20 64 61 74 61 |some binary data|\n" {
t.Error("Expected binary to eq " + binBuffer.String())
}
var htmlBuffer bytes.Buffer
New(configFixture(true), "text/html; charset=utf-8").Format(&htmlBuffer, []byte("<html><span>unfomatted</span></html>"))
if htmlBuffer.String() != "<html><span>unfomatted</span></html>" {
t.Error("Expected html to eq " + htmlBuffer.String())
}
var jsonEnabledBuffer bytes.Buffer
New(configFixture(true), "application/json; charset=utf-8").Format(&jsonEnabledBuffer, []byte("{\"json\": \"some value\"}"))
var targetBuffer bytes.Buffer
jsoncolor.NewFormatter().Format(&targetBuffer, []byte("{\"json\": \"some value\"}"))
target := targetBuffer.String()
if jsonEnabledBuffer.String() != target {
t.Error("Expected json to eq \n" + jsonEnabledBuffer.String() + "\nbut not\n" + target)
}
var jsonDisabledBuffer bytes.Buffer
New(configFixture(false), "application/json; charset=utf-8").Format(&jsonDisabledBuffer, []byte("{\"json\": \"some value\"}"))
if jsonDisabledBuffer.String() != "{\"json\": \"some value\"}" {
t.Error("Expected json to eq " + jsonDisabledBuffer.String())
}
var textBuffer bytes.Buffer
New(configFixture(true), "text/html; charset=utf-8").Format(&textBuffer, []byte("some text"))
if textBuffer.String() != "some text" {
t.Error("Expected text to eq " + textBuffer.String())
}
}
func TestTitle(t *testing.T) {
//binary
title := New(configFixture(true), "octet-stream").Title()
if title != "[binary]" {
t.Error("for octet-stream content type expected title ", title, "to be [binary]")
}
//html
title = New(configFixture(true), "text/html; charset=utf-8").Title()
if title != "[html]" {
t.Error("For text/html content type expected title ", title, " to be [html]")
}
//json
title = New(configFixture(true), "application/json; charset=utf-8").Title()
if title != "[json]" {
t.Error("For text/html content type expected title ", title, " to be [json]")
}
//text
title = New(configFixture(true), "text/plain; charset=utf-8").Title()
if title != "[text]" {
t.Error("For text/html content type expected title ", title, " to be [text]")
}
}
func TestSearchable(t *testing.T) {
if New(configFixture(true), "octet-stream").Searchable() {
t.Error("binary file can't be searchable")
}
if !New(configFixture(true), "text/html").Searchable() {
t.Error("text/html should be searchable")
}
if !New(configFixture(true), "application/json").Searchable() {
t.Error("application/json should be searchable")
}
if !New(configFixture(true), "text/plain").Searchable() {
t.Error("text/plain should be searchable")
}
}
func configFixture(jsonEnabled bool) *config.Config {
return &config.Config{
General: config.GeneralOptions{
FormatJSON: jsonEnabled,
},
}
}

@ -0,0 +1,9 @@
package formatter
type htmlFormatter struct {
textFormatter
}
func (f *htmlFormatter) Title() string {
return "[html]"
}

@ -0,0 +1,28 @@
package formatter
import (
"bytes"
"errors"
"io"
"github.com/nwidger/jsoncolor"
)
type jsonFormatter struct {
textFormatter
}
func (f *jsonFormatter) Format(writer io.Writer, data []byte) error {
jsonFormatter := jsoncolor.NewFormatter()
buf := bytes.NewBuffer(make([]byte, 0, len(data)))
err := jsonFormatter.Format(buf, data)
if err == nil {
writer.Write(buf.Bytes())
return nil
}
return errors.New("json formatter error")
}
func (f *jsonFormatter) Title() string {
return "[json]"
}

@ -0,0 +1,21 @@
package formatter
import (
"io"
)
type textFormatter struct {
}
func (f *textFormatter) Format(writer io.Writer, data []byte) error {
_, err := writer.Write(data)
return err
}
func (f *textFormatter) Title() string {
return "[text]"
}
func (f *textFormatter) Searchable() bool {
return true
}

@ -3,13 +3,11 @@ package main
import (
"bytes"
"compress/gzip"
"encoding/hex"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"mime"
"net/http"
"net/url"
"os"
@ -21,12 +19,12 @@ import (
"time"
"github.com/asciimoo/wuzz/config"
"github.com/asciimoo/wuzz/formatter"
"crypto/tls"
"github.com/jroimartin/gocui"
"github.com/mattn/go-runewidth"
"github.com/nwidger/jsoncolor"
)
const VERSION = "0.2.0"
@ -230,11 +228,6 @@ var METHODS = []string{
http.MethodHead,
}
var CONTENT_TYPES = map[string]string{
"json": "application/json",
"form": "application/x-www-form-urlencoded",
}
const DEFAULT_METHOD = http.MethodGet
var CLIENT = &http.Client{
@ -668,28 +661,14 @@ func (a *App) PrintBody(g *gocui.Gui) {
vrb, _ := g.View(RESPONSE_BODY_VIEW)
vrb.Clear()
responseBody := req.RawResponseBody
// pretty-print json
ctype, _, err := mime.ParseMediaType(req.ContentType)
if err == nil && a.config.General.FormatJSON &&
(ctype == CONTENT_TYPES["json"] || strings.HasSuffix(ctype, "+json")) {
formatter := jsoncolor.NewFormatter()
buf := bytes.NewBuffer(make([]byte, 0, len(req.RawResponseBody)))
err := formatter.Format(buf, req.RawResponseBody)
if err == nil {
responseBody = buf.Bytes()
}
}
responseFormatter := formatter.New(a.config, req.ContentType)
vrb.Title = VIEW_PROPERTIES[vrb.Name()].title + " " + responseFormatter.Title()
is_binary := strings.Index(req.ContentType, "text") == -1 && strings.Index(req.ContentType, "application") == -1
search_text := getViewValue(g, SEARCH_VIEW)
if search_text == "" || is_binary {
vrb.Title = RESPONSE_BODY_VIEW
if is_binary {
vrb.Title += " [binary content]"
fmt.Fprint(vrb, hex.Dump(req.RawResponseBody))
} else {
vrb.Write(responseBody)
search_text := getViewValue(g, "search")
if search_text == "" || !responseFormatter.Searchable() {
err := responseFormatter.Format(vrb, req.RawResponseBody)
if err != nil {
return err
}
if _, err := vrb.Line(0); !a.config.General.PreserveScrollPosition || err != nil {
vrb.SetOrigin(0, 0)
@ -1164,7 +1143,7 @@ func (a *App) ParseArgs(g *gocui.Gui, args []string) error {
arg_index += 1
json_str := args[arg_index]
content_type = "json"
accept_types = append(accept_types, CONTENT_TYPES["json"])
accept_types = append(accept_types, config.ContentTypes["json"])
set_data = true
vdata, _ := g.View(REQUEST_DATA_VIEW)
setViewTextAndCursor(vdata, json_str)
@ -1226,7 +1205,7 @@ func (a *App) ParseArgs(g *gocui.Gui, args []string) error {
}
if !set_binary_data && content_type != "" && !a.hasHeader(g, "Content-Type") {
fmt.Fprintf(vheader, "Content-Type: %v\n", CONTENT_TYPES[content_type])
fmt.Fprintf(vheader, "Content-Type: %v\n", config.ContentTypes[content_type])
}
if len(accept_types) > 0 && !a.hasHeader(g, "Accept") {

Loading…
Cancel
Save