added unit testing
This commit is contained in:
@@ -0,0 +1,278 @@
|
||||
package helper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLogInfo(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
goEnv string
|
||||
message string
|
||||
wantLog bool
|
||||
}{
|
||||
{
|
||||
name: "Development environment",
|
||||
goEnv: "development",
|
||||
message: "Test info message",
|
||||
wantLog: true,
|
||||
},
|
||||
{
|
||||
name: "Debug environment",
|
||||
goEnv: "debug",
|
||||
message: "Test info message",
|
||||
wantLog: true,
|
||||
},
|
||||
{
|
||||
name: "Production environment",
|
||||
goEnv: "production",
|
||||
message: "Test info message",
|
||||
wantLog: true,
|
||||
},
|
||||
{
|
||||
name: "Canary environment",
|
||||
goEnv: "canary",
|
||||
message: "Test info message",
|
||||
wantLog: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Setup
|
||||
os.Setenv("GO_ENV", tt.goEnv)
|
||||
defer os.Unsetenv("GO_ENV")
|
||||
|
||||
// Capture log output
|
||||
var buf bytes.Buffer
|
||||
log.SetOutput(&buf)
|
||||
defer log.SetOutput(os.Stderr)
|
||||
|
||||
// Execute
|
||||
LogInfo(tt.message)
|
||||
|
||||
// Assert
|
||||
logOutput := buf.String()
|
||||
if tt.wantLog && !strings.Contains(logOutput, "INFO:") {
|
||||
t.Errorf("Expected log output to contain 'INFO:', got: %s", logOutput)
|
||||
}
|
||||
if tt.wantLog && !strings.Contains(logOutput, tt.message) {
|
||||
t.Errorf("Expected log output to contain '%s', got: %s", tt.message, logOutput)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogInfo_NoEnvironment(t *testing.T) {
|
||||
// Setup
|
||||
os.Unsetenv("GO_ENV")
|
||||
|
||||
// Capture log output and expect panic/fatal
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
// log.Fatal will exit the program, so we can't really test it directly
|
||||
// But we can ensure it would be called by testing the condition
|
||||
}
|
||||
}()
|
||||
|
||||
// This will call log.Fatal which exits, so we need to test it differently
|
||||
// For now, we'll just ensure the function exists
|
||||
}
|
||||
|
||||
func TestLogWarn(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
goEnv string
|
||||
message string
|
||||
wantLog bool
|
||||
}{
|
||||
{
|
||||
name: "Development environment",
|
||||
goEnv: "development",
|
||||
message: "Test warning message",
|
||||
wantLog: true,
|
||||
},
|
||||
{
|
||||
name: "Debug environment",
|
||||
goEnv: "debug",
|
||||
message: "Test warning message",
|
||||
wantLog: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Setup
|
||||
os.Setenv("GO_ENV", tt.goEnv)
|
||||
defer os.Unsetenv("GO_ENV")
|
||||
|
||||
// Capture log output
|
||||
var buf bytes.Buffer
|
||||
log.SetOutput(&buf)
|
||||
defer log.SetOutput(os.Stderr)
|
||||
|
||||
// Execute
|
||||
LogWarn(tt.message)
|
||||
|
||||
// Assert
|
||||
logOutput := buf.String()
|
||||
if tt.wantLog && !strings.Contains(logOutput, "WARNING:") {
|
||||
t.Errorf("Expected log output to contain 'WARNING:', got: %s", logOutput)
|
||||
}
|
||||
if tt.wantLog && !strings.Contains(logOutput, tt.message) {
|
||||
t.Errorf("Expected log output to contain '%s', got: %s", tt.message, logOutput)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogError(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
goEnv string
|
||||
err error
|
||||
message string
|
||||
wantLog bool
|
||||
}{
|
||||
{
|
||||
name: "Development with error",
|
||||
goEnv: "development",
|
||||
err: errors.New("test error"),
|
||||
message: "Test error message",
|
||||
wantLog: true,
|
||||
},
|
||||
{
|
||||
name: "Development without error",
|
||||
goEnv: "development",
|
||||
err: nil,
|
||||
message: "Test error message",
|
||||
wantLog: true,
|
||||
},
|
||||
{
|
||||
name: "Debug with error",
|
||||
goEnv: "debug",
|
||||
err: errors.New("test error"),
|
||||
message: "Test error message",
|
||||
wantLog: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Setup
|
||||
os.Setenv("GO_ENV", tt.goEnv)
|
||||
defer os.Unsetenv("GO_ENV")
|
||||
|
||||
// Capture log output
|
||||
var buf bytes.Buffer
|
||||
log.SetOutput(&buf)
|
||||
defer log.SetOutput(os.Stderr)
|
||||
|
||||
// Execute
|
||||
LogError(tt.err, tt.message)
|
||||
|
||||
// Assert
|
||||
logOutput := buf.String()
|
||||
if tt.wantLog && !strings.Contains(logOutput, "ERROR:") {
|
||||
t.Errorf("Expected log output to contain 'ERROR:', got: %s", logOutput)
|
||||
}
|
||||
if tt.wantLog && !strings.Contains(logOutput, tt.message) {
|
||||
t.Errorf("Expected log output to contain '%s', got: %s", tt.message, logOutput)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogError_WithNilError(t *testing.T) {
|
||||
// Setup
|
||||
os.Setenv("GO_ENV", "development")
|
||||
defer os.Unsetenv("GO_ENV")
|
||||
|
||||
// Capture log output
|
||||
var buf bytes.Buffer
|
||||
log.SetOutput(&buf)
|
||||
defer log.SetOutput(os.Stderr)
|
||||
|
||||
// Execute
|
||||
LogError(nil, "Message without error")
|
||||
|
||||
// Assert
|
||||
logOutput := buf.String()
|
||||
if !strings.Contains(logOutput, "ERROR:") {
|
||||
t.Errorf("Expected log output to contain 'ERROR:', got: %s", logOutput)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogFatal(t *testing.T) {
|
||||
// Note: We cannot properly test log.Fatal as it calls os.Exit
|
||||
// This test just ensures the function signature is correct
|
||||
// In a real scenario, you'd use a testing framework that can capture os.Exit
|
||||
|
||||
t.Run("Function exists", func(t *testing.T) {
|
||||
// Just verify the function exists and is callable
|
||||
// We won't actually call it to avoid exiting the test
|
||||
// Check that the function type is correct by comparing it to a function pointer
|
||||
var fn func(error, string) = LogFatal
|
||||
if fn == nil {
|
||||
t.Error("LogFatal should not be nil")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestLogging_EnvironmentCheck(t *testing.T) {
|
||||
// Test that all logging functions check for GO_ENV
|
||||
originalEnv := os.Getenv("GO_ENV")
|
||||
defer func() {
|
||||
if originalEnv != "" {
|
||||
os.Setenv("GO_ENV", originalEnv)
|
||||
}
|
||||
}()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
testFunc func()
|
||||
}{
|
||||
{
|
||||
name: "LogInfo",
|
||||
testFunc: func() {
|
||||
os.Setenv("GO_ENV", "development")
|
||||
var buf bytes.Buffer
|
||||
log.SetOutput(&buf)
|
||||
defer log.SetOutput(os.Stderr)
|
||||
LogInfo("test")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "LogWarn",
|
||||
testFunc: func() {
|
||||
os.Setenv("GO_ENV", "development")
|
||||
var buf bytes.Buffer
|
||||
log.SetOutput(&buf)
|
||||
defer log.SetOutput(os.Stderr)
|
||||
LogWarn("test")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "LogError",
|
||||
testFunc: func() {
|
||||
os.Setenv("GO_ENV", "development")
|
||||
var buf bytes.Buffer
|
||||
log.SetOutput(&buf)
|
||||
defer log.SetOutput(os.Stderr)
|
||||
LogError(nil, "test")
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// This should not panic when GO_ENV is set
|
||||
tt.testFunc()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
package helper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRespondWithError(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
statusCode int
|
||||
message string
|
||||
}{
|
||||
{
|
||||
name: "responds with 400 bad request",
|
||||
statusCode: http.StatusBadRequest,
|
||||
message: "Invalid request",
|
||||
},
|
||||
{
|
||||
name: "responds with 401 unauthorized",
|
||||
statusCode: http.StatusUnauthorized,
|
||||
message: "Unauthorized",
|
||||
},
|
||||
{
|
||||
name: "responds with 403 forbidden",
|
||||
statusCode: http.StatusForbidden,
|
||||
message: "Forbidden",
|
||||
},
|
||||
{
|
||||
name: "responds with 404 not found",
|
||||
statusCode: http.StatusNotFound,
|
||||
message: "Not found",
|
||||
},
|
||||
{
|
||||
name: "responds with 500 internal server error",
|
||||
statusCode: http.StatusInternalServerError,
|
||||
message: "Internal server error",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
RespondWithError(w, tt.statusCode, tt.message)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Check status code
|
||||
if resp.StatusCode != tt.statusCode {
|
||||
t.Errorf("status code = %v, want %v", resp.StatusCode, tt.statusCode)
|
||||
}
|
||||
|
||||
// Check content type
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
if contentType != "application/json" {
|
||||
t.Errorf("Content-Type = %v, want application/json", contentType)
|
||||
}
|
||||
|
||||
// Check response body
|
||||
var body map[string]string
|
||||
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
|
||||
t.Fatalf("failed to decode response: %v", err)
|
||||
}
|
||||
|
||||
if body["error"] != tt.message {
|
||||
t.Errorf("error message = %v, want %v", body["error"], tt.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRespondWithMessage(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
message string
|
||||
}{
|
||||
{
|
||||
name: "responds with success message",
|
||||
message: "Operation successful",
|
||||
},
|
||||
{
|
||||
name: "responds with info message",
|
||||
message: "Data updated",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
RespondWithMessage(w, tt.message)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Check response body
|
||||
var body map[string]string
|
||||
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
|
||||
t.Fatalf("failed to decode response: %v", err)
|
||||
}
|
||||
|
||||
if body["message"] != tt.message {
|
||||
t.Errorf("message = %v, want %v", body["message"], tt.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRespondWithJSON(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
statusCode int
|
||||
data interface{}
|
||||
wantJSON string
|
||||
}{
|
||||
{
|
||||
name: "responds with simple map",
|
||||
statusCode: http.StatusOK,
|
||||
data: map[string]string{"key": "value"},
|
||||
wantJSON: `{"key":"value"}`,
|
||||
},
|
||||
{
|
||||
name: "responds with struct",
|
||||
statusCode: http.StatusCreated,
|
||||
data: struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}{ID: 1, Name: "Test"},
|
||||
wantJSON: `{"id":1,"name":"Test"}`,
|
||||
},
|
||||
{
|
||||
name: "responds with array",
|
||||
statusCode: http.StatusOK,
|
||||
data: []string{"item1", "item2"},
|
||||
wantJSON: `["item1","item2"]`,
|
||||
},
|
||||
{
|
||||
name: "responds with nested structure",
|
||||
statusCode: http.StatusOK,
|
||||
data: map[string]interface{}{
|
||||
"user": map[string]string{
|
||||
"name": "John",
|
||||
"role": "admin",
|
||||
},
|
||||
"active": true,
|
||||
},
|
||||
wantJSON: `{"active":true,"user":{"name":"John","role":"admin"}}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
RespondWithJSON(w, tt.statusCode, tt.data)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Check status code
|
||||
if resp.StatusCode != tt.statusCode {
|
||||
t.Errorf("status code = %v, want %v", resp.StatusCode, tt.statusCode)
|
||||
}
|
||||
|
||||
// Check content type
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
if contentType != "application/json" {
|
||||
t.Errorf("Content-Type = %v, want application/json", contentType)
|
||||
}
|
||||
|
||||
// Decode and re-encode to normalize JSON for comparison
|
||||
var got interface{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&got); err != nil {
|
||||
t.Fatalf("failed to decode response: %v", err)
|
||||
}
|
||||
|
||||
var want interface{}
|
||||
if err := json.Unmarshal([]byte(tt.wantJSON), &want); err != nil {
|
||||
t.Fatalf("failed to unmarshal expected JSON: %v", err)
|
||||
}
|
||||
|
||||
gotJSON, _ := json.Marshal(got)
|
||||
wantJSON, _ := json.Marshal(want)
|
||||
|
||||
if string(gotJSON) != string(wantJSON) {
|
||||
t.Errorf("response body = %s, want %s", string(gotJSON), string(wantJSON))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRespondWithJSON_StatusCodes(t *testing.T) {
|
||||
statusCodes := []int{
|
||||
http.StatusOK,
|
||||
http.StatusCreated,
|
||||
http.StatusAccepted,
|
||||
http.StatusNoContent,
|
||||
http.StatusBadRequest,
|
||||
http.StatusUnauthorized,
|
||||
http.StatusForbidden,
|
||||
http.StatusNotFound,
|
||||
http.StatusInternalServerError,
|
||||
}
|
||||
|
||||
for _, code := range statusCodes {
|
||||
t.Run(http.StatusText(code), func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
data := map[string]string{"status": http.StatusText(code)}
|
||||
|
||||
RespondWithJSON(w, code, data)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != code {
|
||||
t.Errorf("status code = %v, want %v", resp.StatusCode, code)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRespondWithError_EmptyMessage(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
RespondWithError(w, http.StatusBadRequest, "")
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
|
||||
var body map[string]string
|
||||
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
|
||||
t.Fatalf("failed to decode response: %v", err)
|
||||
}
|
||||
|
||||
if body["error"] != "" {
|
||||
t.Errorf("error message = %v, want empty string", body["error"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestRespondWithMessage_EmptyMessage(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
RespondWithMessage(w, "")
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
|
||||
var body map[string]string
|
||||
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
|
||||
t.Fatalf("failed to decode response: %v", err)
|
||||
}
|
||||
|
||||
if body["message"] != "" {
|
||||
t.Errorf("message = %v, want empty string", body["message"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestRespondWithJSON_NilData(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
RespondWithJSON(w, http.StatusOK, nil)
|
||||
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Errorf("status code = %v, want %v", resp.StatusCode, http.StatusOK)
|
||||
}
|
||||
|
||||
var body interface{}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
|
||||
t.Fatalf("failed to decode response: %v", err)
|
||||
}
|
||||
|
||||
if body != nil {
|
||||
t.Errorf("body = %v, want nil", body)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user