Skip to content

Update1 README.md #1805

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ go build -o notely && ./notely
*This starts the server in non-database mode.* It will serve a simple webpage at `http://localhost:8080`.

You do *not* need to set up a database or any interactivity on the webpage yet. Instructions for that will come later in the course!
MARGRATENJWENG's version of Boot.dev's Notely app.
388 changes: 388 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,388 @@
package main

import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"

"github.com/bootdotdev/learn-cicd-starter/internal/database"
)

func TestExample(t *testing.T) {
got := 2 + 2
want := 4

if got != want {
t.Errorf("Got %d, want %d", got, want)
}
}

func TestHandlerReadiness(t *testing.T) {
req := httptest.NewRequest("GET", "/v1/healthz", nil)
w := httptest.NewRecorder()

handlerReadiness(w, req)

if w.Code != http.StatusOK {
t.Errorf("Expected status code %d, got %d", http.StatusOK, w.Code)
}

expectedBody := `{"status":"ok"}`
if strings.TrimSpace(w.Body.String()) != expectedBody {
t.Errorf("Expected body %s, got %s", expectedBody, w.Body.String())
}

contentType := w.Header().Get("Content-Type")
if contentType != "application/json" {
t.Errorf("Expected Content-Type 'application/json', got %s", contentType)
}
}

func TestGenerateRandomSHA256Hash(t *testing.T) {
hash1, err := generateRandomSHA256Hash()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}

if len(hash1) != 64 {
t.Errorf("Expected hash length of 64, got %d", len(hash1))
}

// Generate a second hash to ensure they are different (randomness test)
hash2, err := generateRandomSHA256Hash()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}

if hash1 == hash2 {
t.Error("Generated hashes should be different (randomness check)")
}

// Test that hash only contains valid hex characters
for _, r := range hash1 {
if !((r >= '0' && r <= '9') || (r >= 'a' && r <= 'f')) {
t.Errorf("Hash contains invalid character: %c", r)
}
}
}

func TestRespondWithJSON(t *testing.T) {
tests := []struct {
name string
payload interface{}
statusCode int
expectedBody string
}{
{
name: "simple map",
payload: map[string]string{"status": "ok"},
statusCode: 200,
expectedBody: `{"status":"ok"}`,
},
{
name: "string payload",
payload: "hello",
statusCode: 200,
expectedBody: `"hello"`,
},
{
name: "number payload",
payload: 42,
statusCode: 200,
expectedBody: `42`,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
w := httptest.NewRecorder()
respondWithJSON(w, tt.statusCode, tt.payload)

if w.Code != tt.statusCode {
t.Errorf("Expected status code %d, got %d", tt.statusCode, w.Code)
}

if strings.TrimSpace(w.Body.String()) != tt.expectedBody {
t.Errorf("Expected body %s, got %s", tt.expectedBody, w.Body.String())
}

contentType := w.Header().Get("Content-Type")
if contentType != "application/json" {
t.Errorf("Expected Content-Type 'application/json', got %s", contentType)
}
})
}
}

func TestRespondWithError(t *testing.T) {
tests := []struct {
name string
code int
msg string
logErr error
expectedBody string
}{
{
name: "400 error without log error",
code: 400,
msg: "Bad request",
logErr: nil,
expectedBody: `{"error":"Bad request"}`,
},
{
name: "500 error with log error",
code: 500,
msg: "Internal server error",
logErr: nil,
expectedBody: `{"error":"Internal server error"}`,
},
{
name: "404 error",
code: 404,
msg: "Not found",
logErr: nil,
expectedBody: `{"error":"Not found"}`,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
w := httptest.NewRecorder()
respondWithError(w, tt.code, tt.msg, tt.logErr)

if w.Code != tt.code {
t.Errorf("Expected status code %d, got %d", tt.code, w.Code)
}

if strings.TrimSpace(w.Body.String()) != tt.expectedBody {
t.Errorf("Expected body %s, got %s", tt.expectedBody, w.Body.String())
}

contentType := w.Header().Get("Content-Type")
if contentType != "application/json" {
t.Errorf("Expected Content-Type 'application/json', got %s", contentType)
}
})
}
}

func TestDatabaseUserToUser(t *testing.T) {
tests := []struct {
name string
dbUser database.User
expectError bool
}{
{
name: "valid user conversion",
dbUser: database.User{
ID: "123",
CreatedAt: "2023-01-01T00:00:00Z",
UpdatedAt: "2023-01-01T00:00:00Z",
Name: "Test User",
ApiKey: "test-api-key",
},
expectError: false,
},
{
name: "invalid created_at format",
dbUser: database.User{
ID: "123",
CreatedAt: "invalid-date",
UpdatedAt: "2023-01-01T00:00:00Z",
Name: "Test User",
ApiKey: "test-api-key",
},
expectError: true,
},
{
name: "invalid updated_at format",
dbUser: database.User{
ID: "123",
CreatedAt: "2023-01-01T00:00:00Z",
UpdatedAt: "invalid-date",
Name: "Test User",
ApiKey: "test-api-key",
},
expectError: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
user, err := databaseUserToUser(tt.dbUser)

if tt.expectError {
if err == nil {
t.Error("Expected error but got nil")
}
return
}

if err != nil {
t.Errorf("Unexpected error: %v", err)
return
}

if user.ID != tt.dbUser.ID {
t.Errorf("Expected ID %s, got %s", tt.dbUser.ID, user.ID)
}

if user.Name != tt.dbUser.Name {
t.Errorf("Expected Name %s, got %s", tt.dbUser.Name, user.Name)
}

if user.ApiKey != tt.dbUser.ApiKey {
t.Errorf("Expected ApiKey %s, got %s", tt.dbUser.ApiKey, user.ApiKey)
}
})
}
}

func TestDatabaseNoteToNote(t *testing.T) {
tests := []struct {
name string
dbNote database.Note
expectError bool
}{
{
name: "valid note conversion",
dbNote: database.Note{
ID: "note-123",
CreatedAt: "2023-01-01T00:00:00Z",
UpdatedAt: "2023-01-01T00:00:00Z",
Note: "This is a test note",
UserID: "user-123",
},
expectError: false,
},
{
name: "invalid created_at format",
dbNote: database.Note{
ID: "note-123",
CreatedAt: "invalid-date",
UpdatedAt: "2023-01-01T00:00:00Z",
Note: "This is a test note",
UserID: "user-123",
},
expectError: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
note, err := databaseNoteToNote(tt.dbNote)

if tt.expectError {
if err == nil {
t.Error("Expected error but got nil")
}
return
}

if err != nil {
t.Errorf("Unexpected error: %v", err)
return
}

if note.ID != tt.dbNote.ID {
t.Errorf("Expected ID %s, got %s", tt.dbNote.ID, note.ID)
}

if note.Note != tt.dbNote.Note {
t.Errorf("Expected Note %s, got %s", tt.dbNote.Note, note.Note)
}

if note.UserID != tt.dbNote.UserID {
t.Errorf("Expected UserID %s, got %s", tt.dbNote.UserID, note.UserID)
}
})
}
}

func TestDatabasePostsToPosts(t *testing.T) {
tests := []struct {
name string
dbNotes []database.Note
expectError bool
expectedLen int
}{
{
name: "valid notes conversion",
dbNotes: []database.Note{
{
ID: "note-1",
CreatedAt: "2023-01-01T00:00:00Z",
UpdatedAt: "2023-01-01T00:00:00Z",
Note: "First note",
UserID: "user-1",
},
{
ID: "note-2",
CreatedAt: "2023-01-02T00:00:00Z",
UpdatedAt: "2023-01-02T00:00:00Z",
Note: "Second note",
UserID: "user-2",
},
},
expectError: false,
expectedLen: 2,
},
{
name: "empty notes slice",
dbNotes: []database.Note{},
expectError: false,
expectedLen: 0,
},
{
name: "invalid note in slice",
dbNotes: []database.Note{
{
ID: "note-1",
CreatedAt: "invalid-date",
UpdatedAt: "2023-01-01T00:00:00Z",
Note: "First note",
UserID: "user-1",
},
},
expectError: true,
expectedLen: 0,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
notes, err := databasePostsToPosts(tt.dbNotes)

if tt.expectError {
if err == nil {
t.Error("Expected error but got nil")
}
return
}

if err != nil {
t.Errorf("Unexpected error: %v", err)
return
}

if len(notes) != tt.expectedLen {
t.Errorf("Expected length %d, got %d", tt.expectedLen, len(notes))
}

for i, note := range notes {
if i < len(tt.dbNotes) {
if note.ID != tt.dbNotes[i].ID {
t.Errorf("Expected note %d ID %s, got %s", i, tt.dbNotes[i].ID, note.ID)
}
if note.Note != tt.dbNotes[i].Note {
t.Errorf("Expected note %d Note %s, got %s", i, tt.dbNotes[i].Note, note.Note)
}
}
}
})
}
}