pelican/internal/board/card_lifecycle_test.go

321 lines
9.9 KiB
Go
Raw Normal View History

2023-05-06 12:49:40 +01:00
package board_test
import (
"errors"
"os"
"path/filepath"
"reflect"
"sort"
2023-05-06 12:49:40 +01:00
"testing"
"time"
2023-05-06 12:49:40 +01:00
"codeflow.dananglin.me.uk/apollo/pelican/internal/board"
)
func TestCardLifecycle(t *testing.T) {
t.Log("Testing the lifecycle of a couple of cards...")
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_TestCardLifecycle.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, let us create a couple of cards...")
cardArgs := map[int]board.CardArgs{
1: {
NewTitle: "Test Card 01",
NewDescription: "Ensure that the cards are safely stored in the database.",
},
2: {
NewTitle: "Test Card 02",
NewDescription: "Ensure that cards can be modified and that the modifications are saved in the database.",
},
3: {
NewTitle: "Test Card 03",
NewDescription: "Ensure that cards can be deleted from the database.",
},
}
timestamp := time.Now().Format(time.DateTime)
2023-05-06 12:49:40 +01:00
t.Run("Test Create Cards", testCreateCards(kanban, cardArgs))
t.Logf("Now that we've created some cards, let's retrieve one from the database...")
t.Run("Test Read One Card", testReadOneCard(kanban, 1, cardArgs[1], timestamp))
t.Logf("Let us try retrieving multiple cards...")
subCardArgs := make(map[int]board.CardArgs)
subCardArgs[2] = cardArgs[2]
subCardArgs[3] = cardArgs[3]
t.Run("Test Read Multiple Cards", testReadManyCards(kanban, subCardArgs))
2023-05-06 12:49:40 +01:00
t.Logf("Let's see what happens when trying to read a card that does not exist in the database...")
2023-05-06 12:49:40 +01:00
t.Run("Test Read Non-Existent Card", testReadNonExistentCard(kanban, 1000))
2023-05-06 12:49:40 +01:00
t.Logf("Let us try modifying the title and description of one of the cards...")
2023-05-06 12:49:40 +01:00
modifiedCardArgs := board.UpdateCardArgs{
CardID: 1,
CardArgs: board.CardArgs{
NewTitle: cardArgs[1].NewTitle + " (edited).",
NewDescription: "This description has been edited.",
},
}
t.Run("Test Update Card", testUpdateCard(kanban, modifiedCardArgs, timestamp))
t.Logf("Let us also try only modifying the description of a card...")
expectedCardContent := "Only the description is updated in this card."
modifiedCardArgs = board.UpdateCardArgs{
CardID: 2,
CardArgs: board.CardArgs{
NewTitle: "",
NewDescription: expectedCardContent,
},
}
2023-05-06 12:49:40 +01:00
expectedCardTitle := "Test Card 02"
2023-05-06 12:49:40 +01:00
t.Run("Test Update Card Content Only", testUpdateCardContent(kanban, modifiedCardArgs, expectedCardTitle, expectedCardContent, timestamp))
t.Logf("Let's now delete a card from the database...")
t.Run("Test Card Delete", testDeleteCard(kanban, 1, 1, []int{2, 3}))
2023-05-06 12:49:40 +01:00
}
func testCreateCards(kanban board.Board, args map[int]board.CardArgs) func(t *testing.T) {
2023-05-06 12:49:40 +01:00
return func(t *testing.T) {
t.Log("When creating and saving the cards to the database.")
2023-05-06 12:49:40 +01:00
for i := 1; i <= len(args); i++ {
if _, err := kanban.CreateCard(args[i]); err != nil {
t.Fatalf("ERROR: Unable to create the test card, %s.", err)
}
2023-05-06 12:49:40 +01:00
}
t.Logf("%s\tAll cards have been saved to the database.", success)
2023-05-06 12:49:40 +01:00
t.Logf("\tVerifying that the card IDs are present the status in first position...")
2023-05-06 12:49:40 +01:00
statusList, err := kanban.StatusList()
2023-05-06 12:49:40 +01:00
if err != nil {
t.Fatalf("ERROR: Unable to retrieve the list of statuses; %v", err)
2023-05-06 12:49:40 +01:00
}
if len(statusList) == 0 {
t.Fatal("ERROR: No statuses were returned from the database.")
2023-05-06 12:49:40 +01:00
}
expectedStatus := statusList[0]
wantCardIDs := []int{1, 2, 3}
if !reflect.DeepEqual(expectedStatus.CardIds, wantCardIDs) {
t.Errorf("%s\tUnexpected card IDs found in the expected status, want: %v, got %v.", failure, wantCardIDs, expectedStatus.CardIds)
2023-05-06 12:49:40 +01:00
} else {
t.Logf("%s\tExpected card IDs found in the expected status, got %v.", success, expectedStatus.CardIds)
2023-05-06 12:49:40 +01:00
}
}
}
func testReadOneCard(kanban board.Board, cardID int, cardArgs board.CardArgs, wantTimestamp string) func(t *testing.T) {
2023-05-06 12:49:40 +01:00
return func(t *testing.T) {
t.Log("When reading a card from the database.")
2023-05-06 12:49:40 +01:00
card, err := kanban.Card(cardID)
if err != nil {
t.Fatalf("ERROR: Unable to read test card, %s.", err)
}
wantTitle := cardArgs.NewTitle
2023-05-06 12:49:40 +01:00
if card.Title != wantTitle {
t.Errorf("%s\tUnexpected card title received, want: %q, got: %q.", failure, wantTitle, card.Title)
2023-05-06 12:49:40 +01:00
} else {
t.Logf("%s\tExpected card title received, got: %q.", success, card.Title)
2023-05-06 12:49:40 +01:00
}
wantDescription := cardArgs.NewDescription
if card.Description != cardArgs.NewDescription {
t.Errorf("%s\tUnexpected card content received, want: %q, got: %q.", failure, wantDescription, card.Description)
2023-05-06 12:49:40 +01:00
} else {
t.Logf("%s\tExpected card content received, got: %q.", success, card.Description)
2023-05-06 12:49:40 +01:00
}
if card.Created != wantTimestamp {
t.Errorf("%s\tUnexpected timestamp received for the created card, want: %q, got %q.", failure, wantTimestamp, card.Created)
} else {
t.Logf("%s\tExpected timestamp received for the created card, got: %q.", success, card.Created)
}
2023-05-06 12:49:40 +01:00
}
}
func testReadManyCards(kanban board.Board, cardArgs map[int]board.CardArgs) func(t *testing.T) {
2023-05-06 12:49:40 +01:00
return func(t *testing.T) {
t.Log("When reading multiple cards from the database.")
var cardIDList []int
for key := range cardArgs {
cardIDList = append(cardIDList, key)
}
2023-05-06 12:49:40 +01:00
cards, err := kanban.CardList(cardIDList)
if err != nil {
t.Fatalf("ERROR: Unable to retrieve the list of cards from the database; %v", err)
2023-05-06 12:49:40 +01:00
}
for i := range cards {
cardID := cards[i].GetID()
wantTitle := cardArgs[cardID].NewTitle
gotTitle := cards[i].Title
if wantTitle != gotTitle {
t.Errorf("%s\tUnexpected card title received, want: %q, got: %q.", failure, wantTitle, gotTitle)
} else {
t.Logf("%s\tExpected card title received, got: %q.", success, gotTitle)
}
}
}
}
func testReadNonExistentCard(kanban board.Board, cardID int) func(t *testing.T) {
return func(t *testing.T) {
t.Log("When attempting to retrieving a non-existent card from the database.")
_, err := kanban.Card(cardID)
switch {
case err == nil:
t.Errorf("%s\tWanted an error for retrieving a non-existent card but got 'nil' instead.", failure)
case errors.As(err, &board.CardNotExistError{}):
t.Logf("%s\tExpected error received after attempting to retrieve a non-existent card from the database; got '%v'", success, err)
default:
t.Errorf("%s\tUnexpected error received after attempting to retrieve a non-existent card from the database; got: '%v'", failure, err)
}
}
}
func testUpdateCard(kanban board.Board, modifiedCardArgs board.UpdateCardArgs, timestamp string) func(t *testing.T) {
return func(t *testing.T) {
t.Log("When a card is updated in the database.")
if err := kanban.UpdateCard(modifiedCardArgs); err != nil {
2023-05-06 12:49:40 +01:00
t.Fatalf("ERROR: Unable to update the test card, %s", err)
}
got, err := kanban.Card(modifiedCardArgs.CardID)
2023-05-06 12:49:40 +01:00
if err != nil {
t.Fatalf("ERROR: Unable to read the modified test card, %s", err)
}
want := board.Card{
Identity: board.Identity{ID: modifiedCardArgs.CardID},
Title: modifiedCardArgs.NewTitle,
Description: modifiedCardArgs.NewDescription,
Created: timestamp,
2023-05-06 12:49:40 +01:00
}
if !reflect.DeepEqual(got, want) {
t.Errorf("%s\tUnexpected card read from the database: want %+v, got %+v", failure, want, got)
} else {
t.Logf("%s\tExpected card read from the database: got %+v", success, got)
}
}
}
func testUpdateCardContent(kanban board.Board, modifiedCardArgs board.UpdateCardArgs, expectedTitle, expectedDescription, timestamp string) func(t *testing.T) {
2023-05-06 12:49:40 +01:00
return func(t *testing.T) {
t.Log("When (and only when) a card's content is updated in the database.")
if err := kanban.UpdateCard(modifiedCardArgs); err != nil {
2023-05-06 12:49:40 +01:00
t.Fatalf("ERROR: Unable to update the test card, %s", err)
}
got, err := kanban.Card(modifiedCardArgs.CardID)
2023-05-06 12:49:40 +01:00
if err != nil {
t.Fatalf("ERROR: Unable to read the modified test card, %s", err)
}
want := board.Card{
Identity: board.Identity{ID: modifiedCardArgs.CardID},
Title: expectedTitle,
Description: expectedDescription,
Created: timestamp,
2023-05-06 12:49:40 +01:00
}
if !reflect.DeepEqual(got, want) {
t.Errorf("%s\tUnexpected card read from the database, want: %+v, got: %+v", failure, want, got)
} else {
t.Logf("%s\tExpected card read from the database, got: %+v", success, got)
}
}
}
func testDeleteCard(kanban board.Board, cardID, statusID int, expectedCardIDs []int) func(t *testing.T) {
2023-05-06 12:49:40 +01:00
return func(t *testing.T) {
t.Log("When deleting a card from the database.")
args := board.DeleteCardArgs{
CardID: cardID,
StatusID: statusID,
}
if err := kanban.DeleteCard(args); err != nil {
t.Fatalf("ERROR: An error occurred when deleting the card from the database, %v", err)
} else {
t.Logf("%s\tNo errors occurred when deleting the card from the database.", success)
}
t.Logf("\tVerifying that the card is removed from the database...")
_, err := kanban.Card(cardID)
switch {
case err == nil:
2023-05-06 12:49:40 +01:00
t.Errorf("%s\tDid not receive the expected error when attempting to read the deleted card.", failure)
case errors.As(err, &board.CardNotExistError{}):
t.Logf("%s\tSuccessfully received board.CardNotExistError when attempting to retrieve the deleted card.", success)
default:
t.Errorf(
"%s\tDid not receive the expected error when attempting to retrieve the deleted card; got '%v'.",
failure,
err,
)
2023-05-06 12:49:40 +01:00
}
t.Logf("\tVerifying that the card's ID is removed from the status list...")
status, err := kanban.Status(statusID)
if err != nil {
t.Fatalf("ERROR: Unable to read status '%d' from the database; %v", statusID, err)
}
sort.Ints(expectedCardIDs)
sort.Ints(status.CardIds)
if !reflect.DeepEqual(status.CardIds, expectedCardIDs) {
t.Errorf("%s\tUnexpected list of card IDs found in status '%d'; want %v, got %v", failure, statusID, expectedCardIDs, status.CardIds)
2023-05-06 12:49:40 +01:00
} else {
t.Logf("%s\tExpected list of card IDs found in status '%d'; got %v", success, statusID, status.CardIds)
2023-05-06 12:49:40 +01:00
}
}
}