package main import ( "fmt" "github.com/gavv/httpexpect/v2" "strconv" "testing" ) const ( TestGoalName = "Test Goal" ) func startServer(t *testing.T) *httpexpect.Expect { config := ServerConfig{ Datasource: ":memory:", Addr: ":0", Started: make(chan bool), } go start(t.Context(), &config) <-config.Started return httpexpect.Default(t, fmt.Sprintf("http://localhost:%d/api", config.Port)) } func TestGetUsers(t *testing.T) { e := startServer(t) result := e.GET("/users").Expect().Status(200).JSON() result.Array().Length().IsEqual(2) result.Path("$[0].name").InList("Seeseemelk", "Huffle") result.Path("$[1].name").InList("Seeseemelk", "Huffle") } func TestGetUser(t *testing.T) { e := startServer(t) result := e.GET("/user/1").Expect().Status(200).JSON().Object() result.Value("name").IsEqual("Seeseemelk") result.Value("id").IsEqual(1) } func TestGetUserUnknown(t *testing.T) { e := startServer(t) e.GET("/user/999").Expect().Status(404) } func TestGetUserBadId(t *testing.T) { e := startServer(t) e.GET("/user/bad-id").Expect().Status(400) } func TestGetUserGoalsWhenNoGoalsPresent(t *testing.T) { e := startServer(t) result := e.GET("/user/1/goals").Expect().Status(200).JSON().Array() result.Length().IsEqual(0) } func TestGetUserGoals(t *testing.T) { e := startServer(t) // Create a new goal requestBody := map[string]interface{}{ "name": TestGoalName, "target": 5000, "weight": 10, } e.POST("/user/1/goals").WithJSON(requestBody).Expect().Status(201) // Validate goal result := e.GET("/user/1/goals").Expect().Status(200).JSON().Array() result.Length().IsEqual(1) item := result.Value(0).Object() item.Value("id").IsEqual(1) item.Value("name").IsEqual(TestGoalName) item.Value("target").IsEqual(5000) item.Value("weight").IsEqual(10) item.Value("progress").IsEqual(0) item.NotContainsKey("user_id") } func TestGetUserGoalsNoUser(t *testing.T) { e := startServer(t) e.GET("/user/999/goals").Expect().Status(404) } func TestGetUserGoalsBadId(t *testing.T) { e := startServer(t) e.GET("/user/bad-id/goals").Expect().Status(400) } func TestCreateUserGoal(t *testing.T) { e := startServer(t) // Create a new goal requestBody := map[string]interface{}{ "name": TestGoalName, "target": 5000, "weight": 10, } response := e.POST("/user/1/goals"). WithJSON(requestBody). Expect(). Status(201). JSON().Object() // Verify the response has an ID response.ContainsKey("id") goalId := response.Value("id").Number().Raw() // Verify the goal exists in the list of goals goals := e.GET("/user/1/goals"). Expect(). Status(200). JSON().Array() goals.Length().IsEqual(1) goal := goals.Value(0).Object() goal.Value("id").IsEqual(goalId) goal.Value("name").IsEqual(TestGoalName) goal.Value("target").IsEqual(5000) goal.Value("weight").IsEqual(10) goal.Value("progress").IsEqual(0) } func TestCreateUserGoalNoUser(t *testing.T) { e := startServer(t) requestBody := map[string]interface{}{ "name": TestGoalName, "target": 5000, "weight": 10, } e.POST("/user/999/goals"). WithJSON(requestBody). Expect(). Status(404) } func TestCreateUserGoalInvalidInput(t *testing.T) { e := startServer(t) // Test with empty name requestBody := map[string]interface{}{ "name": "", "target": 5000, "weight": 10, } e.POST("/user/1/goals"). WithJSON(requestBody). Expect(). Status(400) // Test with missing fields invalidRequest := map[string]interface{}{ "target": 5000, } e.POST("/user/1/goals"). WithJSON(invalidRequest). Expect(). Status(400) } func TestCreateUserGoalBadId(t *testing.T) { e := startServer(t) requestBody := map[string]interface{}{ "name": TestGoalName, "target": 5000, "weight": 10, } e.POST("/user/bad-id/goals"). WithJSON(requestBody). Expect(). Status(400) } func TestDeleteUserGoal(t *testing.T) { e := startServer(t) // Create a new goal to delete createRequest := map[string]interface{}{ "name": TestGoalName, "target": 1000, "weight": 5, } response := e.POST("/user/1/goals"). WithJSON(createRequest). Expect(). Status(201). JSON().Object() goalId := response.Value("id").Number().Raw() // Delete the goal e.DELETE("/user/1/goal/" + strconv.Itoa(int(goalId))). Expect(). Status(200). JSON().Object().Value("message").IsEqual("Goal deleted successfully") // Verify the goal no longer exists goals := e.GET("/user/1/goals"). Expect(). Status(200). JSON().Array() goals.Length().IsEqual(0) } func TestDeleteUserGoalNotFound(t *testing.T) { e := startServer(t) // Attempt to delete a non-existent goal e.DELETE("/user/1/goal/999"). Expect(). Status(404). JSON().Object().Value("error").IsEqual("Goal not found") } func TestDeleteUserGoalInvalidId(t *testing.T) { e := startServer(t) // Attempt to delete a goal with an invalid ID e.DELETE("/user/1/goal/invalid-id"). Expect(). Status(400). JSON().Object().Value("error").IsEqual("Invalid goal ID") } func TestCreateTask(t *testing.T) { e := startServer(t) // Create a new task without assigned user requestBody := map[string]interface{}{ "name": "Test Task", "reward": 100, } response := e.POST("/tasks"). WithJSON(requestBody). Expect(). Status(201). // Expect Created status JSON().Object() // Verify the response has an ID response.ContainsKey("id") taskId := response.Value("id").Number().Raw() // Create a new task with assigned user assignedUserId := 1 requestBodyWithUser := map[string]interface{}{ "name": "Test Task Assigned", "reward": 200, "assigned": assignedUserId, } responseWithUser := e.POST("/tasks"). WithJSON(requestBodyWithUser). Expect(). Status(201). JSON().Object() responseWithUser.ContainsKey("id") responseWithUser.Value("id").Number().NotEqual(taskId) // Ensure different ID } func TestCreateTaskNoName(t *testing.T) { e := startServer(t) requestBody := map[string]interface{}{ "reward": 100, } e.POST("/tasks").WithJSON(requestBody).Expect().Status(400) } func TestCreateTaskInvalidAssignedUser(t *testing.T) { e := startServer(t) requestBody := map[string]interface{}{ "name": "Test Task Invalid User", "reward": 100, "assigned": 999, // Non-existent user ID } e.POST("/tasks"). WithJSON(requestBody). Expect(). Status(404). // Expect Not Found JSON().Object().Value("error").IsEqual(ErrUserNotFound) } func TestCreateTaskInvalidRequestBody(t *testing.T) { e := startServer(t) // Test with missing fields (name is required) invalidRequest := map[string]interface{}{ "reward": 5000, } e.POST("/tasks"). WithJSON(invalidRequest). Expect(). Status(400) } func TestGetTaskWhenNoTasks(t *testing.T) { e := startServer(t) result := e.GET("/tasks").Expect().Status(200).JSON().Array() result.Length().IsEqual(0) } func createTestTask(e *httpexpect.Expect) { requestBody := map[string]interface{}{ "name": "Test Task", "reward": 100, } e.POST("/tasks").WithJSON(requestBody).Expect().Status(201) } func TestGetTaskSWhenTasks(t *testing.T) { e := startServer(t) createTestTask(e) // Get the task result := e.GET("/tasks").Expect().Status(200).JSON().Array() result.Length().IsEqual(1) item := result.Value(0).Object() item.Value("id").IsEqual(1) item.Value("name").IsEqual("Test Task") item.Value("reward").IsEqual(100) item.Value("assigned").IsNull() } func TestGetTask(t *testing.T) { e := startServer(t) createTestTask(e) result := e.GET("/task/1").Expect().Status(200).JSON().Object() result.Value("id").IsEqual(1) result.Value("name").IsEqual("Test Task") result.Value("reward").IsEqual(100) result.Value("assigned").IsNull() } func TestGetTaskInvalidId(t *testing.T) { e := startServer(t) createTestTask(e) e.GET("/task/2").Expect().Status(404) } func TestGetTaskBadId(t *testing.T) { e := startServer(t) createTestTask(e) e.GET("/task/invalid").Expect().Status(400) } func TestPutTaskModifiesTask(t *testing.T) { e := startServer(t) createTestTask(e) requestBody := map[string]interface{}{ "name": "Updated Task", "reward": 100, } e.PUT("/task/1").WithJSON(requestBody).Expect(). Status(200). JSON().Object() // Verify the task is updated result := e.GET("/task/1").Expect().Status(200).JSON().Object() result.Value("id").IsEqual(1) result.Value("name").IsEqual("Updated Task") result.Value("reward").IsEqual(100) } func TestPutTaskInvalidTaskId(t *testing.T) { e := startServer(t) createTestTask(e) requestBody := map[string]interface{}{ "name": "Updated Task", } e.PUT("/task/999").WithJSON(requestBody).Expect().Status(404) } func TestPostAllowance(t *testing.T) { e := startServer(t) e.POST("/user/1/allowance").WithJSON(PostAllowance{Allowance: 100}).Expect().Status(200) e.POST("/user/1/allowance").WithJSON(PostAllowance{Allowance: 20}).Expect().Status(200) e.POST("/user/1/allowance").WithJSON(PostAllowance{Allowance: -10}).Expect().Status(200) response := e.GET("/user/1").Expect().Status(200).JSON().Object() response.Value("allowance").Number().IsEqual(100 + 20 - 10) } func TestPostAllowanceInvalidUserId(t *testing.T) { e := startServer(t) e.POST("/user/999/allowance").WithJSON(PostAllowance{Allowance: 100}).Expect(). Status(404) }