diff --git a/internal/board/board.go b/internal/board/board.go index 45c10ad..b7e8874 100644 --- a/internal/board/board.go +++ b/internal/board/board.go @@ -205,14 +205,14 @@ func (b *Board) DeleteStatus(statusID int) error { return nil } -// RepositionStatus re-positions a status on the Kanban board. -func (b *Board) RepositionStatus(currentPosition, targetPosition int) error { +// RepositionStatus re-positions a Status value on a slice of Statuses. +func (b *Board) RepositionStatus(currentIndex, targetIndex int) error { statuses, err := b.StatusList() if err != nil { return fmt.Errorf("unable to get the list of statuses; %w", err) } - statuses = moveAndShuffle(statuses, currentPosition, targetPosition) + statuses = moveAndShuffle(statuses, currentIndex, targetIndex) if err := b.normaliseStatusesPositionValues(statuses); err != nil { return fmt.Errorf("unable to normalise the statuses position values; %w", err) diff --git a/internal/board/shuffle.go b/internal/board/shuffle.go index 8375736..a6ac9b0 100644 --- a/internal/board/shuffle.go +++ b/internal/board/shuffle.go @@ -13,10 +13,10 @@ const ( // direction of the move. // This is currently used to move specified columns forwards or backwards on the Kanban board. // When a column changes position the other columns shuffle forward or backwards as required. -func moveAndShuffle(input []Status, currentPosition, targetPosition int) []Status { +func moveAndShuffle(input []Status, currentIndex, targetIndex int) []Status { var shuffle shuffleDirection - if targetPosition < currentPosition { + if targetIndex < currentIndex { // affected elements will need to shuffle backwards if the focused // element moves towards the beginning of the list... shuffle = backwards @@ -30,16 +30,16 @@ func moveAndShuffle(input []Status, currentPosition, targetPosition int) []Statu for ind := range input { switch { - case (shuffle == backwards) && (ind < targetPosition || ind > currentPosition): + case (shuffle == backwards) && (ind < targetIndex || ind > currentIndex): output[ind] = input[ind] - case (shuffle == backwards) && (ind == currentPosition): - output[targetPosition] = input[ind] + case (shuffle == backwards) && (ind == currentIndex): + output[targetIndex] = input[ind] case (shuffle == backwards): output[ind+1] = input[ind] - case (shuffle == forwards) && (ind < currentPosition || ind > targetPosition): + case (shuffle == forwards) && (ind < currentIndex || ind > targetIndex): output[ind] = input[ind] - case (shuffle == forwards) && (ind == currentPosition): - output[targetPosition] = input[ind] + case (shuffle == forwards) && (ind == currentIndex): + output[targetIndex] = input[ind] case (shuffle == forwards): output[ind-1] = input[ind] } diff --git a/internal/board/status_lifecycle_test.go b/internal/board/status_lifecycle_test.go index 691b3ed..8093eb2 100644 --- a/internal/board/status_lifecycle_test.go +++ b/internal/board/status_lifecycle_test.go @@ -2,6 +2,7 @@ package board_test import ( "errors" + "fmt" "os" "path/filepath" "reflect" @@ -57,25 +58,65 @@ func TestStatusLifecycle(t *testing.T) { 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("Our current column positioning is: Backlog, In Progress, Done, On Hold, Next.") + t.Logf("Let us rearrange the board so that the order is: Backlog, Next, In Progress, On Hold, Done...") + + // NOTE: the statuses current index is the index in the slice that is received from the database. + // The wantPositions is used to evaluate each statuses Position value after all the reshuffling and renormalisation. + rearrangeCases := []struct { + statusName string + currentIndex int + targetIndex int + wantPositions map[int]string + }{ + { + statusName: "Done", + currentIndex: 2, + targetIndex: 4, + wantPositions: map[int]string{ + 1: "Backlog", + 2: "In Progress", + 3: "On Hold", + 4: "Next", + 5: "Done", + }, + }, + { + statusName: "Next", + currentIndex: 3, + targetIndex: 1, + wantPositions: map[int]string{ + 1: "Backlog", + 2: "Next", + 3: "In Progress", + 4: "On Hold", + 5: "Done", + }, + }, + } + + for i := range rearrangeCases { + t.Run( + fmt.Sprintf("Test Re-Arrange Status: %s", rearrangeCases[i].statusName), + testRepositionStatuses(kanban, rearrangeCases[i].currentIndex, rearrangeCases[i].targetIndex, rearrangeCases[i].wantPositions), + ) + } 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{ + expectedPositionsAfterDelete := map[int]string{ 1: "Backlog", - 2: "In Progress", - 3: "Done", - 4: "Next", + 2: "Next", + 3: "In Progress", + 4: "Done", } 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.Run("Test Delete Status (On Hold)", testDeleteEmptyStatus(kanban, statusOnHoldExpectedID, expectedPositionsAfterDelete)) 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)) + t.Run("Test Delete a non-empty status", testDeleteNonEmptyStatus(kanban, 2)) } func testCreateStatus(kanban board.Board, name string, position int) func(t *testing.T) { @@ -157,10 +198,31 @@ func testUpdateStatus(kanban board.Board, statusID, expectedPosition int, newNam } } -// func testRearrangeBoard() func(t *testing.T) { -// return func(t *testing.T) { -// } -// } +func testRepositionStatuses(kanban board.Board, currentIndex, targetIndex int, wantPositions map[int]string) func(t *testing.T) { + return func(t *testing.T) { + t.Logf("When repositioning a status on the board.") + + if err := kanban.RepositionStatus(currentIndex, targetIndex); err != nil { + t.Fatalf("ERROR: Unable to reposition the status; %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 testMoveCardToStatus(kanban board.Board) func(t *testing.T) { return func(t *testing.T) { @@ -186,6 +248,8 @@ func testMoveCardToStatus(kanban board.Board) func(t *testing.T) { 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) + } else { + t.Logf("%s\tThe MoveToStatus operation has completed without error.", success) } t.Logf("\tVerifying that the card has moved to '%s'...", status2.Name)