
    ix                        d Z ddlZddlmc mZ ddlZddlZddl	Z	ddl
mZm
Z
 ddlmZ ddlmZmZ ddlZej$                  j'                  d e ee      j,                  j,                               ddlZej2                  defd       Zej2                  defd       Zej2                  defd	       Zej2                  defd
       Z G d d      Z G d d      Z  G d d      Z! G d d      Z" G d d      Z# G d d      Z$ G d d      Z% G d d      Z& G d d      Z' G d d      Z( G d d       Z) G d! d"      Z* G d# d$      Z+ G d% d&      Z,y)'z@Tests for weekly-retro.py - TDD approach (RED first, then GREEN)    N)datedatetime)Path)	MagicMockpatchreturnc                      ddddddddd	dd
ddddddddddddddddddddddddddddddddd d!d"d#dd$dd%d&d'd(ddd)S )*z0Minimal task-timers.json tasks dict for testing.task-1.1	dev1-teamzDeep work taskz2026-03-09T10:00:00z2026-03-09T10:45:00g     @	completed)task_idteam_iddescription
start_timeend_timeduration_secondsstatustask-1.2zMedium work taskz2026-03-10T11:00:00z2026-03-10T11:20:00g     @task-1.3zMicro work taskz2026-03-11T12:00:00z2026-03-11T12:05:00g     r@task-1.4	dev2-teamzDev2 task Az2026-03-09T14:00:00z2026-03-09T14:10:00g     @task-1.5zDev2 task Bz2026-03-10T15:00:00z2026-03-10T15:25:00g     p@task-1.6zDev2 task C (not completed)z2026-03-11T16:00:00N        runningtask-1.7zDeep work task 2z2026-03-12T09:00:00z2026-03-12T10:00:00g      @)r
   r   r   r   r   r   r    r       6/home/jay/workspace/scripts/tests/test_weekly_retro.pysample_tasksr       s    
 ""+/- &!
 ""-/- &!
 "",/- %!
 ""(/- %!
 ""(/- &!
 ""8/ #
 ""-/- &!
o@ @r   c                 `    d| i}|dz  }|j                  t        j                  |             |S )z'Write sample tasks to a temp JSON file.taskstask-timers.json
write_textjsondumps)r    tmp_pathdataps       r   tasks_json_filer+   ]   s3     \"D%%ALLD!"Hr   c                 `    di i}| dz  }|j                  t        j                  |             |S )ztask-timers.json with no tasks.r"   r#   r$   )r(   r)   r*   s      r   empty_tasks_json_filer-   f   s2     R=D%%ALLD!"Hr   c                       	 y)zHSimulated git log output (one line per commit: <hash> <date> <subject>).a@  abc1234 2026-03-09 feat: add new feature
abc1235 2026-03-10 fix: resolve null pointer
abc1236 2026-03-10 fix: another bug
abc1237 2026-03-11 refactor: clean up code
abc1238 2026-03-12 docs: update readme
abc1239 2026-03-12 chore: bump version
abc1240 2026-03-13 some random message
abc1241 2026-03-13 feat: new endpoint
r   r   r   r   sample_git_logr/   o   s    	2	r   c                   *    e Zd Zd Zd Zd Zd Zd Zy)TestLoadTasksc                 N   t        j                  |      }t        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	N   ==z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slenr"   py0py1py3py6assert %(py8)spy8)wr
load_tasksr7   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanation)selfr+   r"   @py_assert2@py_assert5@py_assert4@py_format7@py_format9s           r   test_loads_valid_filez#TestLoadTasks.test_loads_valid_file   s    o.5zQzQzQss55zQr   c                    |dz  }t        j                  |      }i }||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}y )Nzno-file.jsonr4   z%(py0)s == %(py3)sr"   r9   r;   assert %(py5)spy5
r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   )rI   r(   missingr"   rJ   @py_assert1@py_format4@py_format6s           r   )test_returns_empty_dict_when_file_missingz7TestLoadTasks.test_returns_empty_dict_when_file_missing   sr    ^+g&u{uuur   c                    |dz  }|j                  t        j                  di i             t        j                  |      }i }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}y )	Nbad.jsonotherr4   rQ   r"   rR   rS   rT   )r%   r&   r'   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   r(   r*   r"   rJ   rW   rX   rY   s           r   .test_returns_empty_dict_when_tasks_key_missingz<TestLoadTasks.test_returns_empty_dict_when_tasks_key_missing   s    z!	TZZ"./a u{uuur   c                    |dz  }|j                  d       t        j                  |      }i }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}y )	Nr\   z
NOT JSON{{r4   rQ   r"   rR   rS   rT   )r%   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   r^   s           r   'test_returns_empty_dict_on_invalid_jsonz5TestLoadTasks.test_returns_empty_dict_on_invalid_json   s~    z!	\"a u{uuur   c                 z   t        j                  |      }i }||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}y )Nr4   rQ   r"   rR   rS   rT   rU   )rI   r-   r"   rJ   rW   rX   rY   s          r   #test_empty_tasks_returns_empty_dictz1TestLoadTasks.test_empty_tasks_returns_empty_dict   si    34u{uuur   N)__name__
__module____qualname__rO   rZ   r_   ra   rc   r   r   r   r1   r1      s    
r   r1   c                   $    e Zd Zd Zd Zd Zd Zy)TestFilterTasksByWeekc                 P   t        j                  |d      }t        |      }d}||kD  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d x}x}}y )
N2026-11r   )>)z/%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} > %(py6)sr7   resultr8   r=   r>   r?   filter_tasks_by_weekr7   rA   rB   rC   rD   rE   rF   rG   rH   rI   r    rl   rJ   rK   rL   rM   rN   s           r   test_filters_to_correct_weekz2TestFilterTasksByWeek.test_filters_to_correct_week   s    ((yA6{Q{Q{Qss66{Qr   c                 P   t        j                  |d      }t        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d x}x}}y )
Nz2026-09r   r4   r6   r7   rl   r8   r=   r>   rm   ro   s           r    test_excludes_tasks_outside_weekz6TestFilterTasksByWeek.test_excludes_tasks_outside_week   s    ((yA6{a{a{ass66{ar   c                 Z   t        j                  |d      }|j                         D ]  }|d   }d}||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            d x}x}} y )	Nrj   r   r   r4   z%(py1)s == %(py4)sr:   py4assert %(py6)sr<   )r?   rn   valuesrA   rB   rF   rG   rH   )	rI   r    rl   task@py_assert0@py_assert3rJ   @py_format5rM   s	            r   *test_includes_only_completed_when_filteredz@TestFilterTasksByWeek.test_includes_only_completed_when_filtered   sw    ((yAMMO 	1D>0[0>[0000>[000>000[0000000	1r   c                 |   t        j                  i d      }i }||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}y )Nrj   r4   rQ   rl   rR   rS   rT   )
r?   rn   rA   rB   rC   rD   rE   rF   rG   rH   )rI   rl   rJ   rW   rX   rY   s         r   test_empty_tasks_returns_emptyz4TestFilterTasksByWeek.test_empty_tasks_returns_empty   sl    ((Y7v|vvvr   N)rd   re   rf   rp   rr   r}   r   r   r   r   rh   rh      s     
1
r   rh   c                   <    e Zd Zd Zd Zd Zd Zd Zd Zd Z	d Z
y	)
TestClassifySessionc                    t         j                  }d} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}}y 	Ni	  deepr4   zV%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.classify_session
}(%(py4)s)
} == %(py9)sr?   r9   py2rv   r<   py9assert %(py11)spy11
r?   classify_sessionrA   rB   rC   rD   rE   rF   rG   rH   rI   rW   r{   rK   @py_assert8@py_assert7@py_format10@py_format12s           r   test_deep_above_1800z(TestClassifySession.test_deep_above_1800       ""242"4(2F2(F2222(F222222r222r222"2224222(222F22222222r   c                    t         j                  }d} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}}y r   r   r   s           r   test_deep_at_exactly_1801z-TestClassifySession.test_deep_at_exactly_1801   r   r   c                    t         j                  }d} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}}y )	Ni  mediumr4   r   r?   r   r   r   r   r   s           r   test_medium_at_1800z'TestClassifySession.test_medium_at_1800   s    ""444"4(4H4(H4444(H444444r444r444"4444444(444H44444444r   c                    t         j                  }d} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}}y )	NiX  r   r4   r   r?   r   r   r   r   r   s           r   test_medium_at_600z&TestClassifySession.test_medium_at_600   s    ""333"3'383'83333'8333333r333r333"3333333'333833333333r   c                    t         j                  }d} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}}y )	NiW  micror4   r   r?   r   r   r   r   r   s           r   test_micro_below_600z(TestClassifySession.test_micro_below_600   s    ""232"3'272'72222'7222222r222r222"2223222'222722222222r   c                    t         j                  }d} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}}y )	Nr   r   r4   r   r?   r   r   r   r   r   s           r   test_micro_at_zeroz&TestClassifySession.test_micro_at_zero   s    ""010"1%00%0000%000000r000r000"0001000%00000000000r   c                    t         j                  }d} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}}y )	Ni   r   r4   r   r?   r   r   r   r   r   s           r   test_deep_large_valuez)TestClassifySession.test_deep_large_value   r   r   c                    t         j                  }d} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}}y )	Ni  r   r4   r   r?   r   r   r   r   r   s           r   test_medium_midrangez(TestClassifySession.test_medium_midrange   s    ""333"3'383'83333'8333333r333r333"3333333'333833333333r   N)rd   re   rf   r   r   r   r   r   r   r   r   r   r   r   r   r      s*    33543134r   r   c                   6    e Zd Zd Zd Zd Zd Zd Zd Zd Z	y)	TestComputeTeamMetricsc                    |j                         D ci c]  \  }}|d   dk(  s|| }}}t        j                  |      }|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }	d	d
|	iz  }
t        t        j                  |
            d x}x}}|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j
                  |      t        j
                  |      dz  }	d	d
|	iz  }
t        t        j                  |
            d x}x}}y c c}}w )Nr   r   r   
task_count   r4   rt   ru   rw   r<   r      itemsr?   compute_team_metricsrA   rB   rF   rG   rH   )rI   r    kvr   metricsrz   r{   rJ   r|   rM   s              r   test_task_count_per_teamz/TestComputeTeamMetrics.test_task_count_per_team   s    &2&8&8&:Ydaak[>XQTY	Y)))4{#L16Q61Q66661Q6661666Q6666666{#L16Q61Q66661Q6661666Q6666666 Zs
   E	E	c           	         |j                         D ci c]  \  }}|d   dk(  s|| }}}t        j                  |      }|d   d   }t        j                  }d}d}	 |||	      }
||
k(  }|st        j                  d|fd	||
f      t        j                  |      d
t        j                         v st        j                  t              rt        j                  t              nd
t        j                  |      t        j                  |      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}x}	}
y c c}}w )Nr   r   r   avg_duration_secondsg     x@MbP?relr4   z[%(py1)s == %(py11)s
{%(py11)s = %(py5)s
{%(py5)s = %(py3)s.approx
}(%(py7)s, rel=%(py9)s)
}pytestr:   r;   rT   py7r   r   assert %(py13)spy13r   r?   r   r   approxrA   rB   rF   rC   rD   rE   rG   rH   rI   r    r   r   r   r   rz   rL   @py_assert6r   @py_assert10rJ   r   @py_format14s                 r   test_avg_duration_dev1z-TestComputeTeamMetrics.test_avg_duration_dev1      &2&8&8&:Ydaak[>XQTY	Y)))4{#$:;^v}}^V^Y]^}VY]?^^;?^^^^^;?^^^^;^^^^^^v^^^v^^^}^^^V^^^Y]^^^?^^^^^^^^^ Z
   E-E-c           	         |j                         D ci c]  \  }}|d   dk(  s|| }}}t        j                  |      }|d   d   }t        j                  }d}d}	 |||	      }
||
k(  }|st        j                  d|fd	||
f      t        j                  |      d
t        j                         v st        j                  t              rt        j                  t              nd
t        j                  |      t        j                  |      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}x}	}
y c c}}w )Nr   r   r   r   g     h@r   r   r4   r   r   r   r   r   r   r   s                 r   test_avg_duration_dev2z-TestComputeTeamMetrics.test_avg_duration_dev2   r   r   c                    |j                         D ci c]  \  }}|d   dk(  s|| }}}t        j                  |      }|d   d   }|d   }d}||k(  }	|	slt        j                  d|	fd||f      t        j
                  |      t        j
                  |      d	z  }
d
d|
iz  }t        t        j                  |            d x}x}	}|d   }d}||k(  }	|	slt        j                  d|	fd||f      t        j
                  |      t        j
                  |      d	z  }
d
d|
iz  }t        t        j                  |            d x}x}	}|d   }d}||k(  }	|	slt        j                  d|	fd||f      t        j
                  |      t        j
                  |      d	z  }
d
d|
iz  }t        t        j                  |            d x}x}	}y c c}}w )Nr   r   r   session_patternr   r   r4   rt   ru   rw   r<   r      r   r   rI   r    r   r   r   r   sprz   r{   rJ   r|   rM   s               r   test_session_pattern_dev1z0TestComputeTeamMetrics.test_session_pattern_dev1   sB   &2&8&8&:Ydaak[>XQTY	Y)))4[!"34 &zQzQzQzQ(| q |q    |q   |   q       '{a{a{a{a Z
   GGc                    |j                         D ci c]  \  }}|d   dk(  s|| }}}t        j                  |      }|d   d   }|d   }d}||k(  }	|	slt        j                  d|	fd||f      t        j
                  |      t        j
                  |      d	z  }
d
d|
iz  }t        t        j                  |            d x}x}	}|d   }d}||k(  }	|	slt        j                  d|	fd||f      t        j
                  |      t        j
                  |      d	z  }
d
d|
iz  }t        t        j                  |            d x}x}	}|d   }d}||k(  }	|	slt        j                  d|	fd||f      t        j
                  |      t        j
                  |      d	z  }
d
d|
iz  }t        t        j                  |            d x}x}	}y c c}}w )Nr   r   r   r   r   r   r4   rt   ru   rw   r<   r   r   r   r   r   s               r   test_session_pattern_dev2z0TestComputeTeamMetrics.test_session_pattern_dev2   s@   &2&8&8&:Ydaak[>XQTY	Y)))4[!"34&zQzQzQzQ(| q |q    |q   |   q       '{a{a{a{a Zr   c                 z   t        j                  i       }i }||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}y )Nr4   rQ   r   rR   rS   rT   )
r?   r   rA   rB   rC   rD   rE   rF   rG   rH   )rI   r   rJ   rW   rX   rY   s         r   rc   z:TestComputeTeamMetrics.test_empty_tasks_returns_empty_dict  sj    ))"-w"}w"ww"r   c                 
   |j                         D ci c]  \  }}|d   dk(  s|| }}}t        j                  |      }|j                         D ](  }d}||v }|st	        j
                  d|fd||f      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      nddz  }	dd	|	iz  }
t        t	        j                  |
            d
x}}|d   }d}||k(  }|slt	        j
                  d|fd||f      t	        j                  |      t	        j                  |      dz  }dd|iz  }t        t	        j                  |            d
x}x}}+ y
c c}}w )z0fix_pct is set later when commit data is merged.r   r   fix_pctinz%(py1)s in %(py3)s	team_datar:   r;   rS   rT   Nr   r4   rt   ru   rw   r<   )r   r?   r   rx   rA   rB   rF   rC   rD   rE   rG   rH   )rI   r    r   r   r   r   r   rz   rJ   rX   rY   r{   r|   rM   s                 r   ,test_fix_pct_not_set_by_compute_team_metricszCTestComputeTeamMetrics.test_fix_pct_not_set_by_compute_team_metrics  s   &2&8&8&:Ydaak[>XQTY	Y)))4 ) 	/I)9	))))9	)))9))))))	)))	)))))))Y'.3.'3....'3...'...3.......	/ Zs
   E?E?N)
rd   re   rf   r   r   r   r   r   rc   r   r   r   r   r   r      s'    7__	  /r   r   c                   N    e Zd Zd Zd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zy)TestParseGitLogc                 .   t        j                  |      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )Ntotal   r4   rt   ru   rw   r<   r?   parse_git_logrA   rB   rF   rG   rH   rI   r/   rl   rz   r{   rJ   r|   rM   s           r   test_total_commit_countz'TestParseGitLog.test_total_commit_count  s`    !!.1g#!#!####!######!#######r   c                 4   t        j                  |      }|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	Nby_typefeatr   r4   rt   ru   rw   r<   r   r   s           r   test_feat_countzTestParseGitLog.test_feat_count  i    !!.1i (-A-(A----(A---(---A-------r   c                 4   t        j                  |      }|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	Nr   fixr   r4   rt   ru   rw   r<   r   r   s           r   test_fix_countzTestParseGitLog.test_fix_count#  si    !!.1i ',1,'1,,,,'1,,,',,,1,,,,,,,r   c                 4   t        j                  |      }|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	Nr   refactorr   r4   rt   ru   rw   r<   r   r   s           r   test_refactor_countz#TestParseGitLog.test_refactor_count'  si    !!.1i ,11,1111,111,1111111111r   c                 4   t        j                  |      }|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	Nr   docsr   r4   rt   ru   rw   r<   r   r   s           r   test_docs_countzTestParseGitLog.test_docs_count+  r   r   c                 4   t        j                  |      }|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	Nr   chorer   r4   rt   ru   rw   r<   r   r   s           r   test_chore_countz TestParseGitLog.test_chore_count/  i    !!.1i ).Q.)Q....)Q...)...Q.......r   c                 4   t        j                  |      }|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )	Nr   r]   r   r4   rt   ru   rw   r<   r   r   s           r   test_other_countz TestParseGitLog.test_other_count3  r   r   c                 4   t        j                  d      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}|d	   d
   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )N r   r   r4   rt   ru   rw   r<   r   r   r   )rI   rl   rz   r{   rJ   r|   rM   s          r   !test_empty_log_returns_zero_totalz1TestParseGitLog.test_empty_log_returns_zero_total7  s    !!"%g#!#!####!######!#######i (-A-(A----(A---(---A-------r   c                    t        j                  |      }dD ]  }|d   }||v }|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}} y )	N)r   r   r   r   r   r]   r   r   )z%(py0)s in %(py3)strR   rS   rT   )
r?   r   rA   rB   rC   rD   rE   rF   rG   rH   )rI   r/   rl   r   rJ   rW   rX   rY   s           r   !test_all_types_present_in_by_typez1TestParseGitLog.test_all_types_present_in_by_type<  s    !!.1F 	*Ay))1)))))1)))))))1)))1)))))))))))	*r   c                 8   d}t        j                  |      }|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d x}x}}y )
Nz+abc1234 2026-03-09 feat(api): add endpoint
r   r   r   r4   rt   ru   rw   r<   r   rI   logrl   rz   r{   rJ   r|   rM   s           r   test_feat_with_scopez$TestParseGitLog.test_feat_with_scopeA  sn    <!!#&i (-A-(A----(A---(---A-------r   c                 8   d}t        j                  |      }|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d x}x}}y )
Nz)abc1234 2026-03-09 Fix: uppercase prefix
r   r   r   r4   rt   ru   rw   r<   r   r   s           r   test_case_insensitive_prefixz,TestParseGitLog.test_case_insensitive_prefixF  sn    :!!#&i ',1,'1,,,,'1,,,',,,1,,,,,,,r   N)rd   re   rf   r   r   r   r   r   r   r   r   r   r   r  r   r   r   r   r     s9    $.-2.//.
*
.
-r   r   c                       e Zd Zd Zd Zd Zy)TestFetchGitLogc                    t               }d|_        d|_        t        d|      5  t	        j
                  t        d      dd      }d d d        d	}|v }|st        j                  d
|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d x}}y # 1 sw Y   xY w)Nr   z#abc1234 2026-03-09 feat: something
subprocess.runreturn_value/fake
2026-03-09
2026-03-15	workspacesinceuntilzfeat: somethingr   r   outputr   rS   rT   )r   
returncodestdoutr   r?   fetch_git_logr   rA   rB   rF   rC   rD   rE   rG   rH   )rI   mock_resultr  rz   rJ   rX   rY   s          r   test_returns_stdout_on_successz.TestFetchGitLog.test_returns_stdout_on_successR  s    k!"C#+> 	%%w-""F	 !* F**** F*** ******F***F*******	 	s   "C66C?c                    t               }d|_        d|_        t        d|      5  t	        j
                  t        d      dd      }d d d        d}|k(  }|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}y # 1 sw Y   xY w)N   r   r  r  r  r	  r
  r  r4   rQ   r  rR   rS   rT   )r   r  r  r   r?   r  r   rA   rB   rC   rD   rE   rF   rG   rH   )rI   r  r  rJ   rW   rX   rY   s          r   (test_returns_empty_string_on_git_failurez8TestFetchGitLog.test_returns_empty_string_on_git_failure^  s    k!$#+> 	%%w-""F	 v|vvv	 	s   "C77D c                    t        dt        d            5  t        j                  t	        d      dd      }d d d        d}|k(  }|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}y # 1 sw Y   xY w)Nr  zgit not foundside_effectr  r	  r
  r  r   r4   rQ   r  rR   rS   rT   )r   FileNotFoundErrorr?   r  r   rA   rB   rC   rD   rE   rF   rG   rH   )rI   r  rJ   rW   rX   rY   s         r   &test_returns_empty_string_on_exceptionz6TestFetchGitLog.test_returns_empty_string_on_exceptionj  s    #1B?1ST 	%%w-""F	 v|vvv	 	s   "C((C1N)rd   re   rf   r  r  r  r   r   r   r  r  Q  s    
+
r   r  c                   $    e Zd Zd Zd Zd Zd Zy)TestComputeFixPctc                    ddddd}t         j                  } ||      }t        j                  }d} ||      }||k(  }|s{t	        j
                  d|fd||f      d	t        j                         v st	        j                  t               rt	        j                  t               nd	t	        j                  |      d
t        j                         v st	        j                  |      rt	        j                  |      nd
t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      t	        j                  |      dz  }dd|iz  }	t        t	        j                  |	            d x}x}x}x}x}}y )N
      r3   r   r   r   r         >@r4   z%(py5)s
{%(py5)s = %(py2)s
{%(py2)s = %(py0)s.compute_fix_pct
}(%(py3)s)
} == %(py13)s
{%(py13)s = %(py9)s
{%(py9)s = %(py7)s.approx
}(%(py11)s)
}r?   commitsr   r9   r   r;   rT   r   r   r   r   assert %(py15)spy15r?   compute_fix_pctr   r   rA   rB   rC   rD   rE   rF   rG   rH   
rI   r&  rW   rL   r   r   @py_assert12r   r   @py_format16s
             r   test_fix_pct_basicz$TestComputeFixPct.test_fix_pct_basicz  s   1a+@A!!A!'*AfmmADAmD.AA*.AAAAA*.AAAAAAArAAArAAA!AAAAAA'AAA'AAA*AAAAAAfAAAfAAAmAAADAAA.AAAAAAAAAr   c                    ddddd}t         j                  } ||      }t        j                  }d} ||      }||k(  }|s{t	        j
                  d|fd||f      dt        j                         v st	        j                  t               rt	        j                  t               ndt	        j                  |      d	t        j                         v st	        j                  |      rt	        j                  |      nd	t	        j                  |      d
t        j                         v st	        j                  t              rt	        j                  t              nd
t	        j                  |      t	        j                  |      t	        j                  |      dz  }dd|iz  }	t        t	        j                  |	            d x}x}x}x}x}}y )Nr   r   r"  r#  r   r4   r%  r?   r&  r   r'  r(  r)  r*  r,  s
             r   test_fix_pct_zero_when_no_fixz/TestComputeFixPct.test_fix_pct_zero_when_no_fix~  s   1b+AB!!@!'*@fmm@C@mC.@@*.@@@@@*.@@@@@@@r@@@r@@@!@@@@@@'@@@'@@@*@@@@@@f@@@f@@@m@@@C@@@.@@@@@@@@@r   c                    dddid}t         j                  } ||      }t        j                  }d} ||      }||k(  }|s{t	        j
                  d|fd||f      dt        j                         v st	        j                  t               rt	        j                  t               ndt	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      d	t        j                         v st	        j                  t              rt	        j                  t              nd	t	        j                  |      t	        j                  |      t	        j                  |      d
z  }dd|iz  }	t        t	        j                  |	            d x}x}x}x}x}}y )Nr   r   r#  r   r4   r%  r?   r&  r   r'  r(  r)  r*  r,  s
             r   !test_fix_pct_zero_when_no_commitsz3TestComputeFixPct.test_fix_pct_zero_when_no_commits  s   5!*5!!@!'*@fmm@C@mC.@@*.@@@@@*.@@@@@@@r@@@r@@@!@@@@@@'@@@'@@@*@@@@@@f@@@f@@@m@@@C@@@.@@@@@@@@@r   c                    dddid}t         j                  } ||      }t        j                  }d} ||      }||k(  }|s{t	        j
                  d|fd||f      dt        j                         v st	        j                  t               rt	        j                  t               ndt	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      d	t        j                         v st	        j                  t              rt	        j                  t              nd	t	        j                  |      t	        j                  |      t	        j                  |      d
z  }dd|iz  }	t        t	        j                  |	            d x}x}x}x}x}}y )N   r   r#  g      Y@r4   r%  r?   r&  r   r'  r(  r)  r*  r,  s
             r   test_fix_pct_100z"TestComputeFixPct.test_fix_pct_100  s   5!*5!!B!'*BfmmBEBmE.BB*.BBBBB*.BBBBBBBrBBBrBBB!BBBBBB'BBB'BBB*BBBBBBfBBBfBBBmBBBEBBB.BBBBBBBBBr   N)rd   re   rf   r/  r1  r3  r6  r   r   r   r  r  y  s    BAACr   r  c                   0    e Zd Zd Zd Zd Zd Zd Zd Zy)TestDetectAnomaliesc                    dddddddddi}t        j                  |d       }d	 |D        }t        |      }|sd
dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }t        t        j                  |            d x}}d |D        }t        |      }|sd
dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }t        t        j                  |            d x}}y )Nr   r   g     A@     @@r   r   r   r   r   r   r   r   
prev_teamsc              3   0   K   | ]  }d |v xr d|v   yw)r   r   Nr   .0as     r   	<genexpr>zDTestDetectAnomalies.test_fix_pct_anomaly_above_30.<locals>.<genexpr>  s!     J19>6kQ&66J   ,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}anyr9   r   rv   c              3   $   K   | ]  }d |v  
 yw)z35.0%Nr   r@  s     r   rC  zDTestDetectAnomalies.test_fix_pct_anomaly_above_30.<locals>.<genexpr>  s     3A7a<3   
r?   detect_anomaliesrF  rC   rD   rA   rE   rF   rG   rH   )rI   teams	anomaliesrW   r{   r|   s         r   test_fix_pct_anomaly_above_30z1TestDetectAnomalies.test_fix_pct_anomaly_above_30  s     (.,-a#H	
 ''$?	J	JJsJJJJJJJJJsJJJsJJJJJJJJJJJJJJ333s333333333s333s33333333333333r   c                    dddddddddi}t        j                  |d 	      }d
 |D        }t        |      }| }|sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }t        t        j                  |            d x}x}}y )Nr   r   r$  r:  r5  r   r;  r<  r=  c              3   0   K   | ]  }d |v xr d|v   yw)r   r   Nr   r@  s     r   rC  zDTestDetectAnomalies.test_no_fix_pct_anomaly_at_30.<locals>.<genexpr>  s!     NqyA~:+*::NrD  0assert not %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}rF  rG  rJ  )rI   rL  rM  rW   r{   rK   rY   s          r   test_no_fix_pct_anomaly_at_30z1TestDetectAnomalies.test_no_fix_pct_anomaly_at_30  s     (.,-Q#G	
 ''$?	NINN3NNNNNNNNNNNN3NNN3NNNNNNNNNNNNNNr   c                    dddddddddi}dd	ddd
d
dddi}t        j                  ||      }d |D        }t        |      }|sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }t        t        j                  |            d x}}y )Nr   r         $@r:  r   r   r;  r<  r   r5  r=  c              3   0   K   | ]  }d |v xr d|v   yw	   생산성r   Nr   r@  s     r   rC  zCTestDetectAnomalies.test_productivity_drop_50pct.<locals>.<genexpr>  s"     LQ;!#8q(88LrD  rE  rF  rG  rJ  )rI   currentprevrM  rW   r{   r|   s          r   test_productivity_drop_50pctz0TestDetectAnomalies.test_productivity_drop_50pct  s    (.,-Q#G	
  (.,-Q#G	
 ''DA	L)LLsLLLLLLLLLsLLLsLLLLLLLLLLLLLLr   c                    ddddddddd	i}dd
ddddddd	i}t        j                  ||      }d |D        }t        |      }| }|sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }t        t        j                  |            d x}x}}y )Nr   r5  rT  r:  r   r!  r   r;  r<  r   r=  c              3   0   K   | ]  }d |v xr d|v   ywrV  r   r@  s     r   rC  zSTestDetectAnomalies.test_no_productivity_anomaly_when_49pct_drop.<locals>.<genexpr>  s"     P{a'<K1,<<PrD  rQ  rF  rG  rJ  )rI   rX  rY  rM  rW   r{   rK   rY   s           r   ,test_no_productivity_anomaly_when_49pct_dropz@TestDetectAnomalies.test_no_productivity_anomaly_when_49pct_drop  s    (.,-Q#G	
  (.,-Q#G	
 ''DA	PiPP3PPPPPPPPPPPP3PPP3PPPPPPPPPPPPPPr   c                    ddddddddd	i}t        j                  |d 
      }d |D        }t        |      }| }|sddt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      dz  }t        t        j                  |            d x}x}}y )Nr   r5  rT  r:  r   r!  r   r;  r<  r=  c              3   $   K   | ]  }d |v  
 yw)rW  Nr   r@  s     r   rC  zHTestDetectAnomalies.test_no_anomaly_when_no_prev_data.<locals>.<genexpr>  s     ;A{a';rI  rQ  rF  rG  rJ  )rI   rX  rM  rW   r{   rK   rY   s          r   !test_no_anomaly_when_no_prev_dataz5TestDetectAnomalies.test_no_anomaly_when_no_prev_data  s    (.,-Q#G	
 ''DA	;;;3;;;;;;;;;;;;3;;;3;;;;;;;;;;;;;;r   c                    ddddddddddddddddd}d	d
dddddddi}t        j                  ||      }t        |      }d}||k\  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}}y )Nr   g      D@g     @@r   r;  r<  g      I@)r   r   r   r         @r:  r5  r=  r!  )>=)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} >= %(py6)sr7   rM  r8   r=   r>   )r?   rK  r7   rA   rB   rC   rD   rE   rF   rG   rH   )	rI   rL  rY  rM  rJ   rK   rL   rM   rN   s	            r    test_multiple_anomalies_returnedz4TestDetectAnomalies.test_multiple_anomalies_returned  s     (-,-Q#G	  (-,-Q#G	
  (.,-Q#G	
 ''$?	9~""~""""~""""""s"""s""""""9"""9"""~""""""""""r   N)	rd   re   rf   rN  rR  rZ  r]  r`  rd  r   r   r   r8  r8    s#    4
OM(Q,<#r   r8  c                   $    e Zd Zd Zd Zd Zd Zy)TestComputeTrendc                 ~   dddddddddi}dd	dddd
dddi}t        j                  ||      }|d   }t        j                  }d} ||      }||k(  }|st	        j
                  d|fd||f      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      t	        j                  |      dz  }	dd|	iz  }
t        t	        j                  |
            d x}x}x}x}}y )Nr      r:  rb  r5  r   r;  r   r   r   r   r   r   r   task_count_change_pctg      4@r4   )zL%(py1)s == %(py9)s
{%(py9)s = %(py5)s
{%(py5)s = %(py3)s.approx
}(%(py7)s)
}r   )r:   r;   rT   r   r   r   r   r?   compute_trendr   r   rA   rB   rF   rC   rD   rE   rG   rH   )rI   currrY  trendrz   rL   r   r   rJ   r   r   s              r   test_positive_task_count_changez0TestComputeTrend.test_positive_task_count_change  s     (.,-Q#G	
  (.,-Q#G	
   t,,-DDtDt1DD-1DDDDD-1DDDD-DDDDDDDDDDDDDDDtDDD1DDDDDDDDDr   c                    ddddddddd	i}ddd
dddddd	i}t        j                  ||      }|d   }t        j                  }d}| } ||      }||k(  }	|	st	        j
                  d|	fd||f      t	        j                  |      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      t	        j                  |      dz  }
dd|
iz  }t        t	        j                  |            d x}x}	x}x}x}}y )Nr   r         @rb  r!  r5  r   r;  ri  r:  avg_duration_change_pctrT  r4   )zO%(py1)s == %(py10)s
{%(py10)s = %(py5)s
{%(py5)s = %(py3)s.approx
}(-%(py7)s)
}r   )r:   r;   rT   r   py10zassert %(py12)spy12rk  )rI   rm  rY  rn  rz   rL   r   r   @py_assert9rJ   @py_format11@py_format13s               r   !test_negative_avg_duration_changez2TestComputeTrend.test_negative_avg_duration_change  s    (-,-Q#G	
  (.,-Q#G	
   t,./G6==G$G$G=3GG/3GGGGG/3GGGG/GGGGGG6GGG6GGG=GGG$GGG3GGGGGGGGGr   c                    ddddddddd	i}t        j                  |d       }i }||k(  }|st        j                  d
|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}y )Nr   r   rq  rb  r!  r5  r   r;  ri  r4   rQ   rn  rR   rS   rT   )
r?   rl  rA   rB   rC   rD   rE   rF   rG   rH   )rI   rm  rn  rJ   rW   rX   rY   s          r   test_no_prev_dataz"TestComputeTrend.test_no_prev_data+  s     (-,-Q#G	
   t,u{uuur   c                    ddddddddd	i}ddd
dddddd	i}t        j                  ||      }d}||v }|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }t        t        j                  |            d x}}y )Nr   r5  r:  rb  r   r!  r   r;  ri  r   rj  r   r   rn  r   rS   rT   )
r?   rl  rA   rB   rF   rC   rD   rE   rG   rH   )rI   rm  rY  rn  rz   rJ   rX   rY   s           r   +test_zero_prev_task_count_no_division_errorz<TestComputeTrend.test_zero_prev_task_count_no_division_error7  s    (.,-Q#G	
 (+,-Q#G	
   t,&/&%////&%///&//////%///%///////r   N)rd   re   rf   ro  rx  rz  r|  r   r   r   rf  rf    s    E(H(
0r   rf  c                   *    e Zd Zd Zd Zd Zd Zd Zy)TestSnapshotIOc                    |dz  }di d}t        j                  ||d       |dz  }|j                  } |       }|sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        t        j                  |            d x}}y )Nretro-snapshotsrj   weekrL  week-2026-11.jsonAassert %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.exists
}()
}expectedrG  
r?   save_snapshotexistsrC   rD   rA   rE   rF   rG   rH   )rI   r(   snapshot_dirr)   r  rW   r{   r|   s           r   test_save_snapshot_creates_filez.TestSnapshotIO.test_save_snapshot_creates_fileS  s    "33!B/
|Y7"55         x   x             r   c                    |dz  }ddddiid}t        j                  ||d       t        j                  |dz  j	                               }|d   }d}||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}}|d   d   d   }d}||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            d x}x}}y )Nr  rj   r   r   r5  r  r  r  r4   rt   ru   rw   r<   rL  )
r?   r  r&   loads	read_textrA   rB   rF   rG   rH   )
rI   r(   r  r)   savedrz   r{   rJ   r|   rM   s
             r   test_save_snapshot_contentz)TestSnapshotIO.test_save_snapshot_contentZ  s    "33![<:K,LM
|Y7

L+>>IIKLV})	)}	))))}	)))})))	)))))))W~k*<8=A=8A====8A===8===A=======r   c                    |dz  dz  dz  }t        j                  ddi|d       |j                  } |       }|sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        t        j                  |            d x}}y )	Nr   nestedr  r  rj   r  r  rG  r  )rI   r(   r  rW   r{   r|   s         r   )test_save_snapshot_creates_dir_if_missingz8TestSnapshotIO.test_save_snapshot_creates_dir_if_missingb  s    &(836GG
&),lIF""$"$$$$$$$$|$$$|$$$"$$$$$$$$$$r   c                    |dz  }|j                          ddddiid}|dz  j                  t        j                  |             t	        j
                  |d      }d }||u}|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}|d   d   d   }	d}
|	|
k(  }|slt        j                  d|fd|	|
f      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            d x}	x}}
y )Nr  2026-10r   r   r   r  week-2026-10.json)is not)z%(py0)s is not %(py3)sloadedrR   rS   rT   rL  r4   rt   ru   rw   r<   )mkdirr%   r&   r'   r?   load_snapshotrA   rB   rC   rD   rE   rF   rG   rH   )rI   r(   r  r)   r  rJ   rW   rX   rY   rz   r{   r|   rM   s                r   test_load_snapshot_returns_dataz.TestSnapshotIO.test_load_snapshot_returns_datag  s   "33![<:K,LM	+	+77

48HI!!,	:!!vT!!!!vT!!!!!!v!!!v!!!T!!!!!!!g{+L9>Q>9Q>>>>9Q>>>9>>>Q>>>>>>>r   c                    |dz  }|j                          t        j                  |d      }d }||u }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            d x}}y )	Nr  r  )is)z%(py0)s is %(py3)srl   rR   rS   rT   )r  r?   r  rA   rB   rC   rD   rE   rF   rG   rH   )rI   r(   r  rl   rJ   rW   rX   rY   s           r   ,test_load_snapshot_returns_none_when_missingz;TestSnapshotIO.test_load_snapshot_returns_none_when_missingp  s    "33!!,	:v~vvvr   N)rd   re   rf   r  r  r  r  r  r   r   r   r~  r~  R  s    !>%
?r   r~  c                   $    e Zd Zd Zd Zd Zd Zy)TestGetWeekPeriodc                 t   t        j                  d      \  }}t        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d x}x}}t        |      }d
}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d x}x}}y )Nrj   r	  r4   r6   strstartr8   r=   r>   r
  end)r?   get_week_periodr  rA   rB   rC   rD   rE   rF   rG   rH   )rI   r  r  rJ   rK   rL   rM   rN   s           r   test_2026_week_11_periodz*TestGetWeekPeriod.test_2026_week_11_period}  s.   ''	2
s5z)\)z\))))z\))))))s)))s))))))5)))5)))z)))\)))))))3x'<'x<''''x<''''''s'''s''''''3'''3'''x'''<'''''''r   c                 T   t        j                  d      \  }}||z
  }|j                  }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d x}x}x}}y )
Nrj      r4   )z8%(py4)s
{%(py4)s = (%(py0)s - %(py1)s).days
} == %(py7)sr  r  )r9   r:   rv   r   assert %(py9)sr   )r?   r  daysrA   rB   rC   rD   rE   rF   rG   rH   )	rI   r  r  rJ   r{   r   rK   @py_format8r   s	            r   test_period_span_is_7_daysz,TestGetWeekPeriod.test_period_span_is_7_days  s    ''	2
se&!!&Q&!Q&&&&!Q&&&&&&&&&&&&&&&e&&&e&&&!&&&Q&&&&&&&r   c                    t        j                  d      \  }}|j                  } |       }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nrj   r   r4   zF%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.weekday
}()
} == %(py7)sr  r9   r   rv   r   r  r   r?   r  weekdayrA   rB   rC   rD   rE   rF   rG   rH   )	rI   r  _rW   r{   r   rK   r  r   s	            r   test_start_is_mondayz&TestGetWeekPeriod.test_start_is_monday  s    %%i0q}}#}#!#!####!######u###u###}######!#######r   c                    t        j                  d      \  }}|j                  } |       }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}}y )	Nrj   r  r4   r  r  r  r  r   r  )	rI   r  r  rW   r{   r   rK   r  r   s	            r   test_end_is_sundayz$TestGetWeekPeriod.test_end_is_sunday  s    ##I.3{{!{}!!}!!!!}!!!!!!s!!!s!!!{!!!}!!!!!!!!!!r   N)rd   re   rf   r  r  r  r  r   r   r   r  r  |  s    (
'$"r   r  c                       e Zd Zd Zd Zy)TestGetCurrentWeekc                    t        j                         }|j                  d      }t        |      }d}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  t              rt	        j                  t              nddt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d x}x}}t        |d
         t        |d         }	}d}
|
|k  }d}||k  }|r|st	        j
                  d||fd|
||f      t	        j                  |
      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d x}
x}x}}d}
|
|	k  }d}|	|k  }|r|st	        j
                  d||fd|
|	|f      t	        j                  |
      dt        j                         v st	        j                  |	      rt	        j                  |	      ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d x}
x}x}}y )N-r   r4   r6   r7   partsr8   r=   r>   r   r   i  i4  )<=r  )z%(py1)s <= %(py4)sz%(py4)s <= %(py6)syear)r:   rv   r<   5   wnum)r?   get_current_weeksplitr7   rA   rB   rC   rD   rE   rF   rG   rH   int)rI   r  r  rJ   rK   rL   rM   rN   r  r  rz   r{   s               r   test_returns_iso_week_formatz/TestGetCurrentWeek.test_returns_iso_week_format  s   ""$

35zQzQzQss55zQq]CaMd#tt##t#tt#####ttt###t######t###t###t#######qDBDBqDBqDDBr   c                     t        d      5 }t        ddd      |j                  _        d |_        t        j                         }d d d        d}|k(  }|st        j                  d|fd||f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
z  }dd|iz  }t        t        j                  |            d x}}y # 1 sw Y   xY w)Nzweekly_retro.datei  r   r5  c                      t        | i |S )N)r   )rB  kws     r   <lambda>z?TestGetCurrentWeek.test_format_is_zero_padded.<locals>.<lambda>  s    T1^^ r   z2026-02r4   rQ   r  rR   rS   rT   )r   r   todayr  r  r?   r  rA   rB   rC   rD   rE   rF   rG   rH   )rI   	mock_dater  rJ   rW   rX   rY   s          r   test_format_is_zero_paddedz-TestGetCurrentWeek.test_format_is_zero_padded  s    &' 	)9+/a+;IOO($CI!&&(D	) ! ty    ty      t   t   y       		) 	)s   9C44C=N)rd   re   rf   r  r  r   r   r   r  r    s    !r   r  c                   B    e Zd Zd Zd Zd Zd Zd Zd Zd Z	d Z
d	 Zy
)TestBuildReportc                 r   |dz  }t               }d|_        d|_        t        d|      5  t	        j
                  d|||      }d d d        d}|v }|st        j                  d	|fd
||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }	t        t        j                  |	            d x}}d}||v }|st        j                  d	|fd
||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }	t        t        j                  |	            d x}}d}||v }|st        j                  d	|fd
||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }	t        t        j                  |	            d x}}d}||v }|st        j                  d	|fd
||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }	t        t        j                  |	            d x}}d}||v }|st        j                  d	|fd
||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }	t        t        j                  |	            d x}}d}||v }|st        j                  d	|fd
||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }	t        t        j                  |	            d x}}y # 1 sw Y   xY w)Nr  r   zKabc1 2026-03-09 feat: f1
abc2 2026-03-10 fix: f2
abc3 2026-03-11 chore: c1
r  r  rj   r  r  
tasks_filer  r  r   r   reportr   rS   rT   periodrL  r&  rn  rM  )r   r  r  r   r?   build_reportrA   rB   rF   rC   rD   rE   rG   rH   )
rI   r+   r(   r  mock_gitr  rz   rJ   rX   rY   s
             r   test_report_has_required_keysz-TestBuildReport.test_report_has_required_keys  su   "33;p#(; 	__"*)	F	 vvv!x6!!!!x6!!!x!!!!!!6!!!6!!!!!!! w&    w&   w      &   &       "yF""""yF"""y""""""F"""F""""""" w&    w&   w      &   &       ${f$$$${f$$${$$$$$$f$$$f$$$$$$$	 	s   P,,P6c                    |dz  }t               }d|_        d|_        t        d|      5  t	        j
                  d|||      }d d d        d   }d}||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            d x}x}}y # 1 sw Y   xY w)Nr  r   r   r  r  rj   r  r  r4   rt   ru   rw   r<   r   r  r  r   r?   r  rA   rB   rF   rG   rH   rI   r+   r(   r  r  r  rz   r{   rJ   r|   rM   s              r   test_report_week_matches_inputz.TestBuildReport.test_report_week_matches_input  s    "33;#(; 	__"*)	F	 f~**~****~***~**********	 	s   CCc                    |dz  }t               }d|_        d|_        t        d|      5  t	        j
                  d|||      }d d d        d   d	   }d
}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            d x}x}}|d   d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            d x}x}}y # 1 sw Y   xY w)Nr  r   r   r  r  rj   r  r  r  r	  r4   rt   ru   rw   r<   r  r
  r  r  s              r   test_report_period_datesz(TestBuildReport.test_report_period_dates  s   "33;#(; 	__"*)	F	 h(8L8(L8888(L888(888L8888888h&6,6&,6666&,666&666,6666666	 	s   EEc                    |dz  }t               }d|_        d|_        t        d|      5  t	        j
                  d|||      }d d d        d}d	   }||v }|slt        j                  d
|fd||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            d x}x}}y # 1 sw Y   xY w)Nr  r   r   r  r  rj   r  r   rL  r   z%(py1)s in %(py4)sru   rw   r<   r  r  s              r   test_report_teams_include_dev1z.TestBuildReport.test_report_teams_include_dev1  s    "33;#(; 	__"*)	F	 -fWo-{o----{o---{---o-------	 	s   CCc                    |dz  }t               }d|_        d|_        t        d|      5  t	        j
                  d|||      }d d d        d   }i }||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            d x}x}}|d   }g }||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            d x}x}}y # 1 sw Y   xY w)Nr  r   r   r  r  rj   r  rL  r4   rt   ru   rw   r<   rM  r  )rI   r-   r(   r  r  r  rz   r{   rJ   r|   rM   s              r   test_report_with_empty_tasksz,TestBuildReport.test_report_with_empty_tasks  s    "33;#(; 	__"0)	F	 g$"$"$$$$"$$$$$$"$$$$$$$k"(b("b(((("b((("(((b(((((((	 	s   EEc                    |dz  }t        dt              5  t        j                  d|||      }d d d        d   d   }d}||k(  }|slt	        j
                  d	|fd
||f      t	        j                  |      t	        j                  |      dz  }dd|iz  }	t        t	        j                  |	            d x}x}}y # 1 sw Y   xY w)Nr  r  r  rj   r  r&  r   r   r4   rt   ru   rw   r<   )	r   r  r?   r  rA   rB   rF   rG   rH   )
rI   r+   r(   r  r  rz   r{   rJ   r|   rM   s
             r   test_report_with_git_failurez,TestBuildReport.test_report_with_git_failure  s    "33#1BC 	__"*)	F	 i ).Q.)Q....)Q...)...Q.......	 	s   B==Cc                 >   |dz  }t               }d|_        d|_        t        d|      5  t	        j
                  d|||       d d d        d}||z  }|j                  } |       }|sd	d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      t        j                  |      dz  }	t        t        j                  |	            d x}x}x}}y # 1 sw Y   xY w)Nr  r   r   r  r  rj   r  r  zMassert %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = (%(py0)s / %(py2)s).exists
}()
}r  )r9   r   rT   r   )r   r  r  r   r?   r  r  rC   rD   rA   rE   rF   rG   rH   )
rI   r+   r(   r  r  rW   r{   rL   r   r  s
             r   test_snapshot_saved_after_buildz/TestBuildReport.test_snapshot_saved_after_build  s    "33;#(; 	OO"*)		  3<22<2::<:<<<<<<<<<<<<<<2<<<:<<<<<<<<<<	 	s   DDc           	      B   |dz  }|j                          dddddddd	d
did}|dz  j                  t        j                  |             t	               }d|_        d|_        t        d|      5  t        j                  d|||      }d d d        d   }i }||k7  }	|	slt        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            d x}x}	}d}|d   }||v }	|	slt        j                  d|	fd||f      t        j                  |      t        j                  |      dz  }
dd|
iz  }t        t        j                  |            d x}x}	}y # 1 sw Y   
xY w)Nr  r  r      g     @@rb  r   r   r   r;  ri  r  r  r   r   r  r  rj   r  rn  )!=)z%(py1)s != %(py4)sru   rw   r<   rj  r   r  )r  r%   r&   r'   r   r  r  r   r?   r  rA   rB   rF   rG   rH   )rI   r+   r(   r  	prev_datar  r  rz   r{   rJ   r|   rM   s               r   test_trend_uses_prev_snapshotz-TestBuildReport.test_trend_uses_prev_snapshot  sU   "33 "$,2"02a!'L	

	 
+	+77

98MN;#(; 	__"*)	F	 g$"$"$$$$"$$$$$$"$$$$$$$&9&/9&/9999&/999&999/9999999	 	s   2FFc                    |dz  }t               }d|_        d|_        t        d|      5  t	        j
                  d|||      }d d d        d   }t        |t              }|sd	d
t        j                         v st        j                  t              rt        j                  t              nd
t        j                  |      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            d x}}y # 1 sw Y   xY w)Nr  r   r   r  r  rj   r  rn  z5assert %(py5)s
{%(py5)s = %(py0)s(%(py2)s, %(py3)s)
}
isinstancedict)r9   r   r;   rT   )r   r  r  r   r?   r  r  r  rC   rD   rA   rE   rF   rG   rH   )	rI   r+   r(   r  r  r  rW   rL   rY   s	            r   +test_trend_no_prev_returns_empty_or_no_prevz;TestBuildReport.test_trend_no_prev_returns_empty_or_no_prev1  s    "33;#(; 	__"*)	F	 !/0z/400000000z000z000/000000400040000000000	 	s   EEN)rd   re   rf   r  r  r  r  r  r  r  r  r  r   r   r   r  r    s/    %(+7.)	/=:<1r   r  c                       e Zd Zd Zd Zd Zy)TestGetPrevWeekc                    t         j                  }d} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}}y )	Nrj   r  r4   zS%(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.get_prev_week
}(%(py4)s)
} == %(py9)sr?   r   r   r   
r?   get_prev_weekrA   rB   rC   rD   rE   rF   rG   rH   r   s           r   test_week_11_prev_is_10z'TestGetPrevWeek.test_week_11_prev_is_10G      7	7	*7i7*i7777*i777777r777r777777	777*777i77777777r   c                    t        j                  d      }|j                  }d} ||      }|sddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      dz  }t        t        j                  |            d x}x}}y )Nz2026-01z2025-zLassert %(py6)s
{%(py6)s = %(py2)s
{%(py2)s = %(py0)s.startswith
}(%(py4)s)
}rY  )r9   r   rv   r<   )
r?   r  
startswithrC   rD   rA   rE   rF   rG   rH   )rI   rY  rW   r{   rK   rM   s         r   test_week_01_prev_is_last_yearz.TestGetPrevWeek.test_week_01_prev_is_last_yearJ  s~    	*'w'w''''''''t'''t''''''w''''''''''r   c                    t         j                  }d} ||      }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            d x}x}x}x}}y )	Nz2025-52z2025-51r4   r  r?   r   r   r   r  r   s           r   test_week_52_prev_is_51z'TestGetPrevWeek.test_week_52_prev_is_51O  r  r   N)rd   re   rf   r  r  r  r   r   r   r  r  F  s    8(
8r   r  )-__doc__builtinsrC   _pytest.assertion.rewrite	assertionrewriterA   r&   systempfiler   r   pathlibr   unittest.mockr   r   r   pathinsertr  __file__parentweekly_retror?   fixturer  r    r+   r-   r/   r1   rh   r   r   r   r  r  r8  rf  r~  r  r  r  r  r   r   r   <module>r     sj   F    
  #  *  3tH~,,334 5  Bd B BJ t   t     & @ 64 4B3/ 3/v/- /-n   PC C.j# j#dH0 H0`" "T" "0! !.S1 S1v
8 
8r   