WIP improve test coverage
There is a test of Response.Read that is failing and I haven't yet figured out why.
This commit is contained in:
parent
e183f9cd23
commit
4969e33e28
|
@ -0,0 +1 @@
|
|||
coverage.out
|
|
@ -3,6 +3,7 @@ package gemini_test
|
|||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
"net/url"
|
||||
|
||||
"tildegit.org/tjp/gus/gemini"
|
||||
)
|
||||
|
@ -84,3 +85,19 @@ func TestParseRequest(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnescapedQuery(t *testing.T) {
|
||||
table := []string{
|
||||
"foo bar",
|
||||
}
|
||||
|
||||
for _, test := range table {
|
||||
t.Run(test, func(t *testing.T) {
|
||||
u, _ := url.Parse("gemini://domain.com/path?" + url.QueryEscape(test))
|
||||
result := gemini.Request{ URL: u }.UnescapedQuery()
|
||||
if result != test {
|
||||
t.Errorf("expected %q, got %q", test, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,3 +149,169 @@ func TestBuildResponses(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseResponses(t *testing.T) {
|
||||
table := []struct {
|
||||
input string
|
||||
status gemini.Status
|
||||
meta string
|
||||
body string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
input: "20 text/gemini\r\n# you got me!\n",
|
||||
status: gemini.StatusSuccess,
|
||||
meta: "text/gemini",
|
||||
body: "# you got me!\n",
|
||||
},
|
||||
{
|
||||
input: "30 gemini://some.where/else\r\n",
|
||||
status: gemini.StatusTemporaryRedirect,
|
||||
meta: "gemini://some.where/else",
|
||||
},
|
||||
{
|
||||
input: "10 forgot the line ending",
|
||||
err: gemini.InvalidResponseLineEnding,
|
||||
},
|
||||
{
|
||||
input: "10 wrong line ending\n",
|
||||
err: gemini.InvalidResponseLineEnding,
|
||||
},
|
||||
{
|
||||
input: "10no space\r\n",
|
||||
err: gemini.InvalidResponseHeaderLine,
|
||||
},
|
||||
{
|
||||
input: "no status code\r\n",
|
||||
err: gemini.InvalidResponseHeaderLine,
|
||||
},
|
||||
{
|
||||
input: "31 gemini://domain.com/my/new/home\r\n",
|
||||
status: gemini.StatusPermanentRedirect,
|
||||
meta: "gemini://domain.com/my/new/home",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range table {
|
||||
t.Run(test.input, func(t *testing.T) {
|
||||
response, err := gemini.ParseResponse(bytes.NewBufferString(test.input))
|
||||
|
||||
if !errors.Is(err, test.err) {
|
||||
t.Fatalf("expected error %s, got %s", test.err, err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if response.Status != test.status {
|
||||
t.Errorf("expected status %d, got %d", test.status, response.Status)
|
||||
}
|
||||
|
||||
if response.Meta != test.meta {
|
||||
t.Errorf("expected meta %q, got %q", test.meta, response.Meta)
|
||||
}
|
||||
|
||||
if response.Body == nil {
|
||||
if test.body != "" {
|
||||
t.Errorf("expected body %q, got nil", test.body)
|
||||
}
|
||||
} else {
|
||||
body, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("error reading response body: %s", err.Error())
|
||||
}
|
||||
|
||||
if test.body != string(body) {
|
||||
t.Errorf("expected body %q, got %q", test.body, string(body))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResponseClose(t *testing.T) {
|
||||
body := &rdCloser{Buffer: bytes.NewBufferString("the body here")}
|
||||
resp := &gemini.Response{
|
||||
Status: gemini.StatusSuccess,
|
||||
Meta: "text/gemini",
|
||||
Body: body,
|
||||
}
|
||||
|
||||
if err := resp.Close(); err != nil {
|
||||
t.Fatalf("response close error: %s", err.Error())
|
||||
}
|
||||
|
||||
if !body.closed {
|
||||
t.Error("response body was not closed by response.Close()")
|
||||
}
|
||||
|
||||
resp = &gemini.Response{
|
||||
Status: gemini.StatusInput,
|
||||
Meta: "give me more",
|
||||
}
|
||||
|
||||
if err := resp.Close(); err != nil {
|
||||
t.Fatalf("response close error: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
type rdCloser struct {
|
||||
*bytes.Buffer
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (rc *rdCloser) Close() error {
|
||||
rc.closed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestResponseWriteTo(t *testing.T) {
|
||||
// invariant under test: WriteTo() sends the same bytes as Read()
|
||||
|
||||
clone := func(resp *gemini.Response) *gemini.Response {
|
||||
other := &gemini.Response{
|
||||
Status: resp.Status,
|
||||
Meta: resp.Meta,
|
||||
}
|
||||
|
||||
if resp.Body != nil {
|
||||
// the body could be one-time readable, so replace it with a buffer
|
||||
buf, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("error reading response body: %s", err.Error())
|
||||
}
|
||||
resp.Body = bytes.NewBuffer(buf)
|
||||
|
||||
buf2 := make([]byte, len(buf))
|
||||
if copy(buf2, buf) != len(buf) {
|
||||
t.Fatalf("short copy on a []byte")
|
||||
}
|
||||
|
||||
other.Body = bytes.NewBuffer(buf2)
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
r1 := &gemini.Response{
|
||||
Status: gemini.StatusSuccess,
|
||||
Meta: "text/gemini",
|
||||
Body: bytes.NewBufferString("the body goes here"),
|
||||
}
|
||||
r2 := clone(r1)
|
||||
|
||||
wtbuf := &bytes.Buffer{}
|
||||
if _, err := r1.WriteTo(wtbuf); err != nil {
|
||||
t.Fatalf("response.WriteTo(): %s", err.Error())
|
||||
}
|
||||
|
||||
rdbuf := make([]byte, wtbuf.Len())
|
||||
if n, err := r2.Read(rdbuf); err != nil {
|
||||
t.Fatalf("response.Read() -> %d: %s", n, err.Error())
|
||||
}
|
||||
|
||||
if wtbuf.String() != string(rdbuf) {
|
||||
t.Fatalf("Read produced %q but WriteTo produced %q", string(rdbuf), wtbuf.String())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue