package gig

import (

"bytes"

"crypto/tls"

"crypto/x509"

"errors"

"fmt"

"io"

"strings"

"testing"

"text/template"

"github.com/matryer/is"

)

type (

Template struct {

templates *template.Template

}

TemplateFail struct{}

)

func (t *Template) Render(w io.Writer, name string, data interface{}, c Context) error {

return t.templates.ExecuteTemplate(w, name, data)

}

func (t *TemplateFail) Render(w io.Writer, name string, data interface{}, c Context) error {

return errors.New("could not render")

}

func TestContext(t *testing.T) {

g := New()

c, conn := g.NewFakeContext("/", nil)

is := is.New(t)

// Gig

is.True(c.Gig() != nil)

// Conn

if conn == nil {

panic("staticcheck SA5011 false positive, conn cannot be nil here")

}

// Response

is.True(c.Response() != nil)

//--------

// Render

//--------

g.Renderer = &Template{

templates: template.Must(template.New("hello").Parse("Hello, {{.}}!")),

}

err := c.Render("hello", "Jon Snow")

is.NoErr(err)

is.Equal("20 text/gemini\r\nHello, Jon Snow!", conn.Written)

g.Renderer = &TemplateFail{}

err = c.Render("hello", "Jon Snow")

is.True(err != nil)

g.Renderer = nil

err = c.Render("hello", "Jon Snow")

is.True(err != nil)

// Text

c, conn = g.NewFakeContext("/", nil)

err = c.Text("Hello, %s!", "World")

is.NoErr(err)

is.Equal(fmt.Sprintf("%d %s\r\nHello, World!", StatusSuccess, MIMETextPlain), conn.Written)

// Gemini

c, conn = g.NewFakeContext("/", nil)

err = c.Gemini("Hello, %s!", "World")

is.NoErr(err)

is.Equal(fmt.Sprintf("%d %s\r\nHello, World!", StatusSuccess, MIMETextGemini), conn.Written)

// Stream

c, conn = g.NewFakeContext("/", nil)

r := strings.NewReader("response from a stream")

err = c.Stream("application/octet-stream", r)

is.NoErr(err)

is.Equal(fmt.Sprintf("%d application/octet-stream\r\nresponse from a stream", StatusSuccess), conn.Written)

c, conn = g.NewFakeContext("/", nil)

conn.FailAfter = 1

is.True(c.Stream("application/octet-stream", r) != nil)

// Error

c, conn = g.NewFakeContext("/", nil)

c.Error(errors.New("error"))

is.Equal(fmt.Sprintf("%d error\r\n", StatusPermanentFailure), conn.Written)

// Reset

c.Set("foe", "ban")

c.(*context).reset(nil, nil, "", nil)

is.Equal(0, len(c.(*context).store))

is.Equal("", c.Path())

}

func TestContextPath(t *testing.T) {

g := New()

r := g.router

r.add("/users/:id", nil)

c := g.newContext(nil, nil, "", nil)

r.find("/users/1", c)

is := is.New(t)

is.Equal("/users/:id", c.Path())

r.add("/users/:uid/files/:fid", nil)

c = g.newContext(nil, nil, "", nil)

r.find("/users/1/files/1", c)

is.Equal("/users/:uid/files/:fid", c.Path())

}

func TestContextRequestURI(t *testing.T) {

g := New()

c := g.newContext(nil, nil, "/my-uri", nil)

is := is.New(t)

is.Equal("/my-uri", c.RequestURI())

}

func TestContextGetParam(t *testing.T) {

g := New()

is := is.New(t)

r := g.router

r.add("/:foo", func(Context) error { return nil })

c, _ := g.NewFakeContext("/bar", nil)

// round-trip param values with modification

is.Equal("", c.Param("bar"))

// shouldn't explode during Reset() afterwards!

c.(*context).reset(nil, nil, "", nil)

}

func TestContextFile(t *testing.T) {

g := New()

is := is.New(t)

c, conn := g.NewFakeContext("/", nil)

is.NoErr(c.File("_fixture/folder/about.gmi"))

is.Equal("20 text/gemini\r\n# About page\n\n=> / 🏠 Home\n", conn.Written)

c, conn = g.NewFakeContext("/", nil)

is.NoErr(c.File("../../../../../../../../etc/profile"))

is.Equal("59 Bad Request\r\n", conn.Written)

}

func TestContextNoContent(t *testing.T) {

c, conn := New().NewFakeContext("/", nil)

is := is.New(t)

is.NoErr(c.NoContent(StatusRedirectPermanent, "gemini://gus.guru/"))

is.Equal("31 gemini://gus.guru/\r\n", conn.Written)

}

func TestContextStore(t *testing.T) {

c := new(context)

c.Set("name", "Jon Snow")

is := is.New(t)

is.Equal("Jon Snow", c.Get("name"))

}

func BenchmarkContext_Store(b *testing.B) {

b.ReportAllocs()

g := &Gig{}

c := &context{

gig: g,

}

for n := 0; n < b.N; n++ {

c.Set("name", "Jon Snow")

if c.Get("name") != "Jon Snow" {

b.Fail()

}

}

}

func TestContextHandler(t *testing.T) {

g := New()

r := g.router

b := new(bytes.Buffer)

r.add("/handler", func(Context) error {

_, err := b.Write([]byte("handler"))

return err

})

c := g.newContext(nil, nil, "", nil)

r.find("/handler", c)

err := c.Handler()(c)

is := is.New(t)

is.Equal("handler", b.String())

is.NoErr(err)

}

func TestContext_Path(t *testing.T) {

path := "/pa/th"

c := new(context)

is := is.New(t)

c.path = path

is.Equal(path, c.Path())

}

func TestContext_QueryString(t *testing.T) {

queryString := "some+val"

c, _ := New().NewFakeContext("/?"+queryString, nil)

is := is.New(t)

q, err := c.QueryString()

is.NoErr(err)

is.Equal("some val", q)

}

func TestContext_IP(t *testing.T) {

c, _ := New().NewFakeContext("/", nil)

is := is.New(t)

is.Equal("192.0.2.1", c.IP())

}

func TestContext_Certificate(t *testing.T) {

c, _ := New().NewFakeContext("/", nil)

is := is.New(t)

is.Equal(c.Certificate(), nil)

cert := &x509.Certificate{}

c, _ = New().NewFakeContext("/", &tls.ConnectionState{

PeerCertificates: []*x509.Certificate{cert},

})

is.Equal(cert, c.Certificate())

}

func TestContext_bytefmt(t *testing.T) {

is := is.New(t)

is.Equal(bytefmt(12345678), "12.3MB")

}


Source