diff --git a/internal/board/board.go b/internal/board/board.go index d0fb331..a41493b 100644 --- a/internal/board/board.go +++ b/internal/board/board.go @@ -184,7 +184,6 @@ func (b *Board) UpdateStatus(args UpdateStatusArgs) error { // DeleteStatus deletes a status from the database. // A status can only be deleted if it does not contain any cards. -// TODO: Create two test cases for this function. func (b *Board) DeleteStatus(statusID int) error { status, err := b.Status(statusID) if err != nil { @@ -199,6 +198,35 @@ func (b *Board) DeleteStatus(statusID int) error { return fmt.Errorf("unable to delete the status from the database; %w", err) } + if err := b.normaliseStatusesPositionValues(); err != nil { + return fmt.Errorf("unable to normalise the statuses position values; %w", err) + } + + return nil +} + +// normaliseStatusesPositionValues retrieves the ordered list of statuses from the database and sets +// each status' positional value based on its position in the list. +func (b *Board) normaliseStatusesPositionValues() error { + statuses, err := b.StatusList() + if err != nil { + return fmt.Errorf("unable to get the list of statuses; %w", err) + } + + for i, status := range statuses { + updateArgs := UpdateStatusArgs{ + StatusID: status.ID, + StatusArgs: StatusArgs{ + Name: "", + Position: i + 1, + }, + } + + if err := b.UpdateStatus(updateArgs); err != nil { + return fmt.Errorf("unable to update the status %q; %w", status.Name, err) + } + } + return nil } diff --git a/internal/board/status_lifecycle_test.go b/internal/board/status_lifecycle_test.go index 5247ee2..6b8a288 100644 --- a/internal/board/status_lifecycle_test.go +++ b/internal/board/status_lifecycle_test.go @@ -1,6 +1,7 @@ package board_test import ( + "errors" "os" "path/filepath" "reflect" @@ -50,14 +51,28 @@ func TestStatusLifecycle(t *testing.T) { t.Run("Test Read Status (Next)", testReadStatus(kanban, statusNextExpectedID, statusNextName, statusNextExpectedBoardPosition)) t.Logf("Let us now update the names of two of our statuses...") - t.Run("Test Status Update (In Progress)", testUpdateStatus(kanban, 2, 2, "In Progress")) - t.Run("Test Status Update (Backlog)", testUpdateStatus(kanban, 1, 1, "Backlog")) + 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")) // (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...") 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)) } func testCreateStatus(kanban board.Board, name string, position int) func(t *testing.T) { @@ -204,8 +219,46 @@ func testMoveCardToStatus(kanban board.Board) func(t *testing.T) { } } -func testDeleteStatus(kanban board.Board) func(t *testing.T) { +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) + } } }