Skip to content

Commit

Permalink
added tests for major pine methods and small improvement to rate limi…
Browse files Browse the repository at this point in the history
…t implementation
  • Loading branch information
BryanMwangi committed Oct 31, 2024
1 parent 2613746 commit 63ed3fd
Show file tree
Hide file tree
Showing 12 changed files with 1,120 additions and 12 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ go.work.sum

# env file
.env

./uploads
Binary file added Examples/FileExample/benchmark.mp4
Binary file not shown.
40 changes: 40 additions & 0 deletions Examples/FileExample/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package main

import (
"log"
"net/http"

"github.com/BryanMwangi/pine"
"github.com/BryanMwangi/pine/cors"
)

func main() {
app := pine.New()

app.Use(cors.New(cors.Config{
AllowedOrigins: []string{"*"},
}))

app.Post("/upload", func(c *pine.Ctx) error {
file, header, err := c.FormFile("file")
if err != nil {
return c.SendStatus(http.StatusInternalServerError)
}
defer file.Close()
err = c.SaveFile(file, header)
if err != nil {
return c.SendStatus(http.StatusInternalServerError)
}
return c.SendString("successfully uploaded file: " + header.Filename)
})

app.Get("/stream", func(c *pine.Ctx) error {
return c.StreamFile("./benchmark.mp4")
})

app.Get("/send", func(c *pine.Ctx) error {
return c.SendFile("./server.log")
})

log.Fatal(app.Start(":3001"))
}
4 changes: 4 additions & 0 deletions Examples/FileExample/server.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
2024/09/29 22:18:57 INFO: Received ping
2024/09/29 22:19:10 INFO: Received ping
2024/09/29 22:19:16 INFO: Received ping
2024/09/29 22:19:19 INFO: Received ping
6 changes: 4 additions & 2 deletions bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,10 @@ func isZeroValue(val reflect.Value) bool {
switch val.Kind() {
case reflect.String:
return val.String() == ""
case reflect.Int, reflect.Int64, reflect.Float64:
return val.Int() == 0 || val.Float() == 0.0
case reflect.Int, reflect.Int64:
return val.Int() == 0
case reflect.Float32, reflect.Float64:
return val.Float() == 0.0
case reflect.Bool:
return !val.Bool()
case reflect.Slice, reflect.Array:
Expand Down
91 changes: 91 additions & 0 deletions bind_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package pine

import (
"bytes"
"errors"
"net/http"
"net/http/httptest"
"testing"
)

func TestBindJSON_Success(t *testing.T) {
body := `{"name": "John", "age": 30}`
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBufferString(body))
ctx := &Ctx{Request: req}

var data struct {
Name string `json:"name"`
Age int `json:"age"`
}

err := ctx.BindJSON(&data)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}

if data.Name != "John" || data.Age != 30 {
t.Fatalf("expected name 'John' and age 30, got name '%s' and age %d", data.Name, data.Age)
}
}

func TestBindJSON_InvalidJSON(t *testing.T) {
body := `{"name": "John", "age":}`
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewBufferString(body))
ctx := &Ctx{Request: req}

var data struct {
Name string `json:"name"`
Age int `json:"age"`
}

err := ctx.BindJSON(&data)
if !errors.Is(err, ErrParse) {
t.Fatalf("expected ErrParse, got %v", err)
}
}

func TestBindParam_Success(t *testing.T) {
ctx := Mock_Ctx()

var id int
err := ctx.BindParam("id", &id)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if id != 42 {
t.Fatalf("expected id to be 42, got %d", id)
}
}

func TestBindParam_NotFound(t *testing.T) {
ctx := Mock_Ctx()

var id int
err := ctx.BindParam("missing", &id)
if !errors.Is(err, ErrValidation) {
t.Fatalf("expected ErrValidation, got %v", err)
}
}

func TestBindQuery_Success(t *testing.T) {
ctx := Mock_Ctx()

var value string
err := ctx.BindQuery("query", &value)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if value != "queryValue" {
t.Fatalf("expected query value to be 'queryValue', got '%s'", value)
}
}

func TestBindQuery_NotFound(t *testing.T) {
ctx := Mock_Ctx()

var value string
err := ctx.BindQuery("missing", &value)
if !errors.Is(err, ErrValidation) {
t.Fatalf("expected ErrValidation, got %v", err)
}
}
171 changes: 171 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package pine

import (
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"testing"
"time"
)

func TestNewClient(t *testing.T) {
client := NewClient()
if client == nil {
t.Fatal("expected non-nil client")
}
if client.Client == nil {
t.Fatal("expected default http client")
}
}

func TestNewClientWithTimeout(t *testing.T) {
timeout := 2 * time.Second
client := NewClientWithTimeout(timeout)
if client == nil {
t.Fatal("expected non-nil client")
}
if client.Client.Timeout != timeout {
t.Fatalf("expected timeout to be %v, got %v", timeout, client.Client.Timeout)
}
}

func TestRequest_JSON(t *testing.T) {
client := NewClient()
req := client.Request()
testBody := map[string]string{"key": "value"}

if err := req.JSON(testBody); err != nil {
t.Fatalf("expected no error, got %v", err)
}
if req.body == nil {
t.Fatal("expected body to be set")
}

expectedContentType := "application/json"
if req.Header.Get("Content-Type") != expectedContentType {
t.Fatalf("expected Content-Type to be %s, got %s", expectedContentType, req.Header.Get("Content-Type"))
}

var result map[string]string
if err := json.NewDecoder(req.body).Decode(&result); err != nil {
t.Fatalf("failed to decode body: %v", err)
}
if result["key"] != "value" {
t.Errorf("expected key to be 'value', got %s", result["key"])
}
}

func TestRequest_SetHeaders(t *testing.T) {
client := NewClient()
req := client.Request()

headers := map[string]string{"X-Custom-Header": "value"}
req.SetHeaders(headers)

if req.Header.Get("X-Custom-Header") != "value" {
t.Fatalf("expected header X-Custom-Header to be 'value', got %s", req.Header.Get("X-Custom-Header"))
}
}

func TestRequest_SetRequestURI(t *testing.T) {
client := NewClient()
req := client.Request()
uri := "https://example.com/api"

req.SetRequestURI(uri)
if req.uri != uri {
t.Fatalf("expected uri to be %s, got %s", uri, req.uri)
}
}

func TestRequest_SetMethod(t *testing.T) {
client := NewClient()
req := client.Request()
method := "GET"

req.SetMethod(method)
if req.method != method {
t.Fatalf("expected method to be %s, got %s", method, req.method)
}
}

func TestClient_SendRequest(t *testing.T) {
// Setup a test server
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("success"))
}))
defer ts.Close()

client := NewClient()
req := client.Request()
req.SetRequestURI(ts.URL).SetMethod("GET")

err := client.SendRequest()
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if client.res.StatusCode != http.StatusOK {
t.Fatalf("expected status code 200, got %d", client.res.StatusCode)
}
}

func TestClient_SendRequest_MissingURI(t *testing.T) {
client := NewClient()
req := client.Request()
req.SetMethod("GET")

err := client.SendRequest()
if !errors.Is(err, ErrURIRequired) {
t.Fatalf("expected ErrURIRequired, got %v", err)
}
}

func TestClient_SendRequest_MissingMethod(t *testing.T) {
client := NewClient()
req := client.Request()
req.SetRequestURI("https://example.com")

err := client.SendRequest()
if !errors.Is(err, ErrMethodRequired) {
t.Fatalf("expected ErrMethodRequired, got %v", err)
}
}

func TestClient_ReadResponse(t *testing.T) {
// Setup a test server
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("response body"))
}))
defer ts.Close()

client := NewClient()
req := client.Request()
req.SetRequestURI(ts.URL).SetMethod("GET")

if err := client.SendRequest(); err != nil {
t.Fatalf("expected no error, got %v", err)
}

code, body, err := client.ReadResponse()
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if code != http.StatusOK {
t.Fatalf("expected status code 200, got %d", code)
}
if string(body) != "response body" {
t.Fatalf("expected body 'response body', got %s", body)
}
}

func TestClient_ReadResponse_NoResponse(t *testing.T) {
client := NewClient()

_, _, err := client.ReadResponse()
if !errors.Is(err, ErrResponseIsNil) {
t.Fatalf("expected ErrResponseIsNil, got %v", err)
}
}
Loading

0 comments on commit 63ed3fd

Please sign in to comment.