pelican/internal/board/status_lifecycle_test.go

265 lines
8.7 KiB
Go
Raw Normal View History

2023-05-06 12:49:40 +01:00
package board_test
import (
"errors"
2023-05-06 12:49:40 +01:00
"os"
"path/filepath"
"reflect"
"testing"
"codeflow.dananglin.me.uk/apollo/pelican/internal/board"
)
func TestStatusLifecycle(t *testing.T) {
t.Log("Testing the lifecycle of the statuses on the Kanban board...")
2023-05-06 12:49:40 +01:00
projectDir, err := projectRoot()
if err != nil {
t.Fatalf(err.Error())
}
testDBPath := filepath.Join(projectDir, "test", "databases", "Board_TestStatusLifecycle.db")
os.Remove(testDBPath)
kanban, err := board.Open(testDBPath)
if err != nil {
t.Fatalf("Unable to open the test Kanban board, %s.", err)
}
defer func() {
_ = kanban.Close()
}()
t.Logf("We've opened a new board with the default list of statuses: 'To Do', 'Doing' and 'Done'")
t.Logf("Let us now create a new status called 'On Hold' in the 4th position...")
2023-05-06 12:49:40 +01:00
statusOnHoldName := "On Hold"
statusOnHoldExpectedID := 4
statusOnHoldBoardPosition := 4
t.Run("Test Create Status (On Hold)", testCreateStatus(kanban, statusOnHoldName, statusOnHoldBoardPosition))
t.Run("Test Read Status (On Hold)", testReadStatus(kanban, statusOnHoldExpectedID, statusOnHoldName, statusOnHoldBoardPosition))
t.Logf("Additionally, let us create another status without specifying a position. It should take the last position on the board...")
statusNextName := "Next"
statusNextExpectedID := 5
statusNextExpectedBoardPosition := 5
2023-05-06 12:49:40 +01:00
t.Run("Test Create Status (Next)", testCreateStatus(kanban, statusNextName, 0))
t.Run("Test Read Status (Next)", testReadStatus(kanban, statusNextExpectedID, statusNextName, statusNextExpectedBoardPosition))
2023-05-06 12:49:40 +01:00
t.Logf("Let us now update the names of two of our statuses...")
t.Run("Test Status Update (Doing to In Progress)", testUpdateStatus(kanban, 2, 2, "In Progress"))
t.Run("Test Status Update (To Do to Backlog)", testUpdateStatus(kanban, 1, 1, "Backlog"))
2023-05-06 12:49:40 +01:00
// (TODO: Rearranging statuses still needs to be implemented)
// Rearrange the board so the order is: Backlog, Next, In Progress, On Hold, Done
t.Logf("Let us now try moving a card from one status to another...")
2023-05-06 12:49:40 +01:00
t.Run("Test Move Card To Status", testMoveCardToStatus(kanban))
// TODO: This needs to be updated when we re-arrange the board.
expectedPositions := map[int]string{
1: "Backlog",
2: "In Progress",
3: "Done",
4: "Next",
}
t.Logf("Let us now delete the 'On Hold' status from the database...")
t.Run("Test Delete Status (On Hold)", testDeleteEmptyStatus(kanban, statusOnHoldExpectedID, expectedPositions))
t.Logf("Additionally, let us try to delete a status that contains a card...")
t.Run("Test Delete a non-empty status", testDeleteNonEmptyStatus(kanban, 3))
2023-05-06 12:49:40 +01:00
}
func testCreateStatus(kanban board.Board, name string, position int) func(t *testing.T) {
2023-05-06 12:49:40 +01:00
return func(t *testing.T) {
t.Log("When the status is created and saved to the database.")
args := board.StatusArgs{
Name: name,
Position: position,
2023-05-06 12:49:40 +01:00
}
if err := kanban.CreateStatus(args); err != nil {
t.Fatalf("ERROR: Unable to create the new status, %v.", err)
}
t.Logf("%s\tStatus '%s' was successfully saved to the database.", success, name)
}
}
func testReadStatus(kanban board.Board, statusID int, wantName string, wantPosition int) func(t *testing.T) {
2023-05-06 12:49:40 +01:00
return func(t *testing.T) {
t.Log("When the status is read from the database.")
status, err := kanban.Status(statusID)
if err != nil {
t.Fatalf("ERROR: Unable to read the test status, %v", err)
}
if status.Name != wantName {
t.Errorf("%s\tUnexpected status received from the database, want: '%s', got: '%s'", failure, wantName, status.Name)
} else {
t.Logf("%s\tSuccessfully received the '%s' status from the database.", success, status.Name)
}
if status.Position != wantPosition {
t.Errorf("%s\tUnexpected position found for %s, want: '%d', got: '%d'", failure, status.Name, wantPosition, status.Position)
} else {
t.Logf("%s\tSuccessfully received the expected position number for the '%s' status, got : '%d'.", success, status.Name, status.Position)
}
2023-05-06 12:49:40 +01:00
}
}
func testUpdateStatus(kanban board.Board, statusID, expectedPosition int, newName string) func(t *testing.T) {
2023-05-06 12:49:40 +01:00
return func(t *testing.T) {
t.Log("When the status' name is updated in the database.")
args := board.UpdateStatusArgs{
StatusID: statusID,
StatusArgs: board.StatusArgs{
Name: newName,
Position: -1,
2023-05-06 12:49:40 +01:00
},
}
if err := kanban.UpdateStatus(args); err != nil {
t.Fatalf("ERROR: Unable to update the status, %v", err)
} else {
t.Logf("%s\tStatus successfully updated.", success)
}
t.Log("\tVerifying the new status...")
status, err := kanban.Status(statusID)
if err != nil {
t.Fatalf("ERROR: Unable to retrieve the status from the database, %v", err)
}
want := board.Status{
ID: statusID,
Name: newName,
CardIds: nil,
Position: expectedPosition,
2023-05-06 12:49:40 +01:00
}
if !reflect.DeepEqual(status, want) {
t.Errorf("%s\tUnexpected status received from the database, want: %+v, got: %+v", failure, want, status)
} else {
t.Logf("%s\tExpected status name received from the database, got: %+v", success, status)
}
}
}
// func testRearrangeBoard() func(t *testing.T) {
// return func(t *testing.T) {
// }
// }
func testMoveCardToStatus(kanban board.Board) func(t *testing.T) {
return func(t *testing.T) {
t.Log("When moving a card between statuses.")
title := "Test card."
cardArgs := board.CardArgs{NewTitle: title, NewDescription: ""}
2023-05-06 12:49:40 +01:00
cardID, err := kanban.CreateCard(cardArgs)
if err != nil {
t.Fatalf("ERROR: Unable to create the card in the database, %v", err)
}
statusList, err := kanban.StatusList()
if err != nil {
t.Fatalf("ERROR: Unable to retrieve the list of statuses from the database, %v", err)
}
status0, status2 := statusList[0], statusList[2]
moveArgs := board.MoveToStatusArgs{CardID: cardID, CurrentStatusID: status0.ID, NextStatusID: status2.ID}
if err := kanban.MoveToStatus(moveArgs); err != nil {
t.Fatalf("ERROR: Unable to move the Card ID from '%s' to '%s', %v", status0.Name, status2.Name, err)
}
t.Logf("\tVerifying that the card has moved to '%s'...", status2.Name)
statusList, err = kanban.StatusList()
if err != nil {
t.Fatalf("ERROR: Unable to retrieve the list of statuses from the database, %v", err)
}
status0, status2 = statusList[0], statusList[2]
if len(status0.CardIds) != 0 {
t.Errorf("%s\tUnexpected number of card IDs found in '%s', want: 0, got: %d", failure, status0.Name, len(status0.CardIds))
} else {
t.Logf("%s\tThe number of card IDs in '%s' is now %d", success, status0.Name, len(status0.CardIds))
}
if len(status2.CardIds) != 1 {
t.Errorf("%s\tUnexpected number of card IDs found in '%s', want: 1, got: %d", failure, status2.Name, len(status2.CardIds))
} else {
t.Logf("%s\tThe number of card IDs in '%s' is now %d", success, status2.Name, len(status2.CardIds))
}
card, err := kanban.Card(status2.CardIds[0])
if err != nil {
t.Fatalf("ERROR: Unable to retrieve the card from the database, %v", err)
}
if card.Title != title {
t.Errorf("%s\tUnexpected card title found in '%s', want: '%s', got: '%s'", success, status2.Name, title, card.Title)
} else {
t.Logf("%s\tExpected card title found in '%s', got: '%s'", success, status2.Name, card.Title)
}
}
}
func testDeleteEmptyStatus(kanban board.Board, statusID int, wantPositions map[int]string) func(t *testing.T) {
return func(t *testing.T) {
t.Log("When deleting an empty status.")
err := kanban.DeleteStatus(statusID)
if err != nil {
t.Fatalf("ERROR: an error was received when attempting to delete the status from the database; %v", err)
}
statuses, err := kanban.StatusList()
if err != nil {
t.Fatalf("ERROR: an error was received when attempting to get the list of statuses from the database; %v", err)
}
gotPositions := make(map[int]string)
for _, status := range statuses {
gotPositions[status.Position] = status.Name
}
if !reflect.DeepEqual(wantPositions, gotPositions) {
t.Errorf("%s\tUnexpected positions received from the database; want: %v, got %v", failure, wantPositions, gotPositions)
} else {
t.Logf("%s\tExpected positions received from the database; got %v", success, gotPositions)
}
}
}
func testDeleteNonEmptyStatus(kanban board.Board, statusID int) func(t *testing.T) {
return func(t *testing.T) {
t.Log("When deleting a non-empty status.")
err := kanban.DeleteStatus(statusID)
switch {
case err == nil:
t.Errorf("%s\tExpected an error for deleting a non-empty status but received 'nil'", failure)
case errors.As(err, &board.StatusNotEmptyError{}):
t.Logf("%s\tExpected error received after attempting to delete a non-empty status; got: '%v'", success, err)
default:
t.Errorf("%s\tUnexpected error received after attempting to delete a non-empty status; got: '%v'", failure, err)
}
}
}