@@ -228,6 +228,175 @@ func TestDashboardSummary_DefaultWIPKeys_PreserveLegacySplit(t *testing.T) {
228228 }
229229}
230230
231+ func TestDashboardSummary_UnassignedTodoExcludedEvenInActiveSprint (t * testing.T ) {
232+ st , cleanup := newTestStore (t )
233+ defer cleanup ()
234+
235+ ctx , user := dashboardTestContext (t , st )
236+
237+ project , err := st .CreateProject (ctx , "Unassigned Active Sprint" )
238+ if err != nil {
239+ t .Fatalf ("CreateProject: %v" , err )
240+ }
241+ now := time .Now ().UTC ()
242+ sprint , err := st .CreateSprint (ctx , project .ID , "Sprint 1" , now .Add (- time .Hour ), now .Add (14 * 24 * time .Hour ))
243+ if err != nil {
244+ t .Fatalf ("CreateSprint: %v" , err )
245+ }
246+ if err := st .ActivateSprint (ctx , project .ID , sprint .ID ); err != nil {
247+ t .Fatalf ("ActivateSprint: %v" , err )
248+ }
249+
250+ points := int64 (3 )
251+ if _ , err := st .CreateTodo (ctx , project .ID , CreateTodoInput {
252+ Title : "Unassigned sprint work" ,
253+ ColumnKey : DefaultColumnDoing ,
254+ EstimationPoints : & points ,
255+ SprintID : & sprint .ID ,
256+ }, ModeFull ); err != nil {
257+ t .Fatalf ("CreateTodo: %v" , err )
258+ }
259+
260+ summary , err := st .GetDashboardSummary (ctx , user .ID , "UTC" )
261+ if err != nil {
262+ t .Fatalf ("GetDashboardSummary: %v" , err )
263+ }
264+ if summary .AssignedCount != 0 || summary .TotalAssignedStoryPoints != 0 {
265+ t .Fatalf ("expected no assigned work, got count=%d points=%d" , summary .AssignedCount , summary .TotalAssignedStoryPoints )
266+ }
267+ if summary .AssignedSplit == nil {
268+ t .Fatal ("expected assigned split" )
269+ }
270+ if * summary .AssignedSplit != (AssignedSplit {}) {
271+ t .Fatalf ("expected empty assigned split, got %+v" , * summary .AssignedSplit )
272+ }
273+
274+ items , _ , err := st .ListDashboardTodos (ctx , user .ID , 10 , nil , "activity" )
275+ if err != nil {
276+ t .Fatalf ("ListDashboardTodos: %v" , err )
277+ }
278+ if len (items ) != 0 {
279+ t .Fatalf ("expected no dashboard todos, got %+v" , items )
280+ }
281+ }
282+
283+ func TestDashboardSummary_AssignedTodoInActiveSprintCountsAsSprint (t * testing.T ) {
284+ st , cleanup := newTestStore (t )
285+ defer cleanup ()
286+
287+ ctx , user := dashboardTestContext (t , st )
288+
289+ project , err := st .CreateProject (ctx , "Assigned Active Sprint" )
290+ if err != nil {
291+ t .Fatalf ("CreateProject: %v" , err )
292+ }
293+ now := time .Now ().UTC ()
294+ if _ , err := st .CreateSprint (ctx , project .ID , "Sprint 0" , now .Add (time .Hour ), now .Add (7 * 24 * time .Hour )); err != nil {
295+ t .Fatalf ("CreateSprint setup: %v" , err )
296+ }
297+ sprint , err := st .CreateSprint (ctx , project .ID , "Sprint 1" , now .Add (- time .Hour ), now .Add (14 * 24 * time .Hour ))
298+ if err != nil {
299+ t .Fatalf ("CreateSprint: %v" , err )
300+ }
301+ if sprint .ID == user .ID {
302+ t .Fatalf ("test setup requires sprint ID to differ from user ID; both were %d" , user .ID )
303+ }
304+ if err := st .ActivateSprint (ctx , project .ID , sprint .ID ); err != nil {
305+ t .Fatalf ("ActivateSprint: %v" , err )
306+ }
307+
308+ points := int64 (3 )
309+ todo , err := st .CreateTodo (ctx , project .ID , CreateTodoInput {
310+ Title : "Assigned sprint work" ,
311+ ColumnKey : DefaultColumnDoing ,
312+ AssigneeUserID : & user .ID ,
313+ EstimationPoints : & points ,
314+ SprintID : & sprint .ID ,
315+ }, ModeFull )
316+ if err != nil {
317+ t .Fatalf ("CreateTodo: %v" , err )
318+ }
319+
320+ summary , err := st .GetDashboardSummary (ctx , user .ID , "UTC" )
321+ if err != nil {
322+ t .Fatalf ("GetDashboardSummary: %v" , err )
323+ }
324+ if summary .AssignedCount != 1 || summary .TotalAssignedStoryPoints != points {
325+ t .Fatalf ("expected assigned count=1 points=%d, got count=%d points=%d" , points , summary .AssignedCount , summary .TotalAssignedStoryPoints )
326+ }
327+ if summary .AssignedSplit == nil {
328+ t .Fatal ("expected assigned split" )
329+ }
330+ if summary .AssignedSplit .SprintCount != 1 || summary .AssignedSplit .SprintPoints != points {
331+ t .Fatalf ("expected active sprint work in sprint bucket, got %+v" , * summary .AssignedSplit )
332+ }
333+ if summary .AssignedSplit .BacklogCount != 0 || summary .AssignedSplit .BacklogPoints != 0 {
334+ t .Fatalf ("expected empty backlog bucket, got %+v" , * summary .AssignedSplit )
335+ }
336+
337+ items , _ , err := st .ListDashboardTodos (ctx , user .ID , 10 , nil , "activity" )
338+ if err != nil {
339+ t .Fatalf ("ListDashboardTodos: %v" , err )
340+ }
341+ if len (items ) != 1 || items [0 ].ID != todo .ID {
342+ t .Fatalf ("expected active sprint todo in dashboard list, got %+v" , items )
343+ }
344+ }
345+
346+ func TestDashboardSummary_AssignedTodoInPlannedSprintCountsAsBacklog (t * testing.T ) {
347+ st , cleanup := newTestStore (t )
348+ defer cleanup ()
349+
350+ ctx , user := dashboardTestContext (t , st )
351+
352+ project , err := st .CreateProject (ctx , "Planned Sprint Workload" )
353+ if err != nil {
354+ t .Fatalf ("CreateProject: %v" , err )
355+ }
356+ now := time .Now ().UTC ()
357+ sprint , err := st .CreateSprint (ctx , project .ID , "Sprint 1" , now .Add (time .Hour ), now .Add (14 * 24 * time .Hour ))
358+ if err != nil {
359+ t .Fatalf ("CreateSprint: %v" , err )
360+ }
361+
362+ points := int64 (3 )
363+ todo , err := st .CreateTodo (ctx , project .ID , CreateTodoInput {
364+ Title : "Assigned planned sprint work" ,
365+ ColumnKey : DefaultColumnDoing ,
366+ AssigneeUserID : & user .ID ,
367+ EstimationPoints : & points ,
368+ SprintID : & sprint .ID ,
369+ }, ModeFull )
370+ if err != nil {
371+ t .Fatalf ("CreateTodo: %v" , err )
372+ }
373+
374+ summary , err := st .GetDashboardSummary (ctx , user .ID , "UTC" )
375+ if err != nil {
376+ t .Fatalf ("GetDashboardSummary: %v" , err )
377+ }
378+ if summary .AssignedCount != 1 || summary .TotalAssignedStoryPoints != points {
379+ t .Fatalf ("expected assigned count=1 points=%d, got count=%d points=%d" , points , summary .AssignedCount , summary .TotalAssignedStoryPoints )
380+ }
381+ if summary .AssignedSplit == nil {
382+ t .Fatal ("expected assigned split" )
383+ }
384+ if summary .AssignedSplit .SprintCount != 0 || summary .AssignedSplit .SprintPoints != 0 {
385+ t .Fatalf ("expected planned sprint work outside current sprint bucket, got %+v" , * summary .AssignedSplit )
386+ }
387+ if summary .AssignedSplit .BacklogCount != 1 || summary .AssignedSplit .BacklogPoints != points {
388+ t .Fatalf ("expected planned sprint work in backlog bucket, got %+v" , * summary .AssignedSplit )
389+ }
390+
391+ items , _ , err := st .ListDashboardTodos (ctx , user .ID , 10 , nil , "activity" )
392+ if err != nil {
393+ t .Fatalf ("ListDashboardTodos: %v" , err )
394+ }
395+ if len (items ) != 1 || items [0 ].ID != todo .ID {
396+ t .Fatalf ("expected planned sprint todo in dashboard list, got %+v" , items )
397+ }
398+ }
399+
231400func TestListDashboardTodos_CustomDoneKeyExcludesDone (t * testing.T ) {
232401 st , cleanup := newTestStore (t )
233402 defer cleanup ()
0 commit comments