package board_test import ( "errors" "os" "path/filepath" "reflect" "testing" "time" "codeflow.dananglin.me.uk/apollo/pelican/internal/board" ) func TestCardLifecycle(t *testing.T) { t.Log("Testing the lifecycle of a card.") 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() }() initialCardTitle := "A test card." initialCardContent := "Ensure that this card is safely stored in the database." expectedCardID := 1 expectedStatusID := 1 timestamp := time.Now().Format(time.DateTime) t.Run("Test Create Card", testCreateCard(kanban, initialCardTitle, initialCardContent, expectedCardID, expectedStatusID)) t.Run("Test Read Card", testReadCard(kanban, expectedCardID, initialCardTitle, initialCardContent, timestamp)) modifiedCardTitle := "Test card updated." modifiedCardContent1 := "Ensure that this card is safely updated in the database." t.Run("Test Update Card", testUpdateCard(kanban, expectedCardID, modifiedCardTitle, modifiedCardContent1, timestamp)) modifiedCardContent2 := "Updated card content only." t.Run("Test Update Card Content", testUpdateCardContent(kanban, expectedCardID, modifiedCardTitle, modifiedCardContent2, timestamp)) t.Run("Test Card Delete", testDeleteCard(kanban, expectedCardID, expectedStatusID)) } func testCreateCard(kanban board.Board, title, content string, expectedCardID, expectedStatusID int) func(t *testing.T) { return func(t *testing.T) { t.Log("When the card is created and saved to the database.") args := board.CardArgs{ NewTitle: title, NewDescription: content, } if _, err := kanban.CreateCard(args); err != nil { t.Fatalf("ERROR: Unable to create the test card, %s.", err) } t.Logf("\t\tVerifying that the card's ID is in the expected status...") status, err := kanban.Status(expectedStatusID) if err != nil { t.Fatalf("ERROR: Unable to read status '%d', %v", expectedStatusID, err) } numCardIDs := len(status.CardIds) if numCardIDs != 1 { t.Fatalf("ERROR: Unexpected number of cards in status '%d', want: %d, got %d.", expectedStatusID, 1, numCardIDs) } if expectedCardID != status.CardIds[0] { t.Errorf("%s\tUnexpected card ID found in the default status, want: %d, got %d.", failure, expectedCardID, status.CardIds[0]) } else { t.Logf("%s\tExpected card ID found in the default status, got %d.", success, status.CardIds[0]) } } } func testReadCard(kanban board.Board, cardID int, wantTitle, wantDescription, wantTimestamp string) func(t *testing.T) { return func(t *testing.T) { t.Log("When a card is read from the database.") card, err := kanban.Card(cardID) if err != nil { t.Fatalf("ERROR: Unable to read test card, %s.", err) } if card.Title != wantTitle { t.Errorf("%s\tUnexpected card title received, want: %s, got: %s.", failure, wantTitle, card.Title) } else { t.Logf("%s\tExpected card title received, got: %s.", success, card.Title) } if card.Description != wantDescription { t.Errorf("%s\tUnexpected card content received, want: %s, got: %s.", failure, wantDescription, card.Description) } else { t.Logf("%s\tExpected card content received, got: %s.", success, card.Description) } if card.Created != wantTimestamp { t.Errorf("%s\tUnexpected timestamp received for the created card, want: %s, got %s.", failure, wantTimestamp, card.Created) } else { t.Logf("%s\tExpected timestamp received for the created card, got: %s.", success, card.Created) } } } func testUpdateCard(kanban board.Board, cardID int, newTitle, newContent, timestamp string) func(t *testing.T) { return func(t *testing.T) { t.Log("When a card is updated in the database.") args := board.UpdateCardArgs{ CardID: cardID, CardArgs: board.CardArgs{ NewTitle: newTitle, NewDescription: newContent, }, } if err := kanban.UpdateCard(args); err != nil { t.Fatalf("ERROR: Unable to update the test card, %s", err) } got, err := kanban.Card(cardID) if err != nil { t.Fatalf("ERROR: Unable to read the modified test card, %s", err) } want := board.Card{ ID: cardID, Title: newTitle, Description: newContent, Created: timestamp, } 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, cardID int, expectedTitle, newContent, timestamp string) func(t *testing.T) { return func(t *testing.T) { t.Log("When (and only when) a card's content is updated in the database.") args := board.UpdateCardArgs{ CardID: cardID, CardArgs: board.CardArgs{ NewTitle: "", NewDescription: newContent, }, } if err := kanban.UpdateCard(args); err != nil { t.Fatalf("ERROR: Unable to update the test card, %s", err) } got, err := kanban.Card(cardID) if err != nil { t.Fatalf("ERROR: Unable to read the modified test card, %s", err) } want := board.Card{ ID: cardID, Title: expectedTitle, Description: newContent, Created: timestamp, } 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) func(t *testing.T) { 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) if err == nil { t.Errorf("%s\tDid not receive the expected error when attempting to read the deleted card.", failure) } else { if errors.Is(err, board.CardNotExistError{}) { t.Errorf( "%s\tDid not receive the expected board.CardNotExistError when attempting to retrieve the deleted card, instead got '%v'.", failure, err, ) } else { t.Logf("%s\tSuccessfully received board.CardNotExistError when attempting to retrieve the deleted card.", success) } } 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) } numCardIDs := len(status.CardIds) if numCardIDs != 0 { t.Errorf("%s\tUnexpected non-empty list of card IDs in status '%d', got '%+v' card IDs.", failure, statusID, status.CardIds) } else { t.Logf("%s\tThe card ID was successfully removed from the list of card in status '%d'.", success, statusID) } } }