
    Ri\F                     <   d Z ddlZddlZddl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 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 health-score.py - TDD approach (RED first, then GREEN)    N)Path)	MagicMockpatchc                   L    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)TestGradeCalculationzTest grade boundariesc                 8    t        j                  d      dk(  sJ y )NZ   Ahsscore_to_gradeselfs    P/home/jay/workspace/.worktrees/task-2117-dev1/scripts/tests/test_health_score.pytest_grade_A_at_90z'TestGradeCalculation.test_grade_A_at_90         $+++    c                 8    t        j                  d      dk(  sJ y )Nd   r
   r   r   s    r   test_grade_A_at_100z(TestGradeCalculation.test_grade_A_at_100   s      %,,,r   c                 8    t        j                  d      dk(  sJ y )NY   Br   r   s    r   test_grade_B_at_89z'TestGradeCalculation.test_grade_B_at_89   r   r   c                 8    t        j                  d      dk(  sJ y )NP   r   r   r   s    r   test_grade_B_at_80z'TestGradeCalculation.test_grade_B_at_80   r   r   c                 8    t        j                  d      dk(  sJ y )NO   Cr   r   s    r   test_grade_C_at_79z'TestGradeCalculation.test_grade_C_at_79!   r   r   c                 8    t        j                  d      dk(  sJ y )NF   r    r   r   s    r   test_grade_C_at_70z'TestGradeCalculation.test_grade_C_at_70$   r   r   c                 8    t        j                  d      dk(  sJ y )NE   Dr   r   s    r   test_grade_D_at_69z'TestGradeCalculation.test_grade_D_at_69'   r   r   c                 8    t        j                  d      dk(  sJ y )N<   r'   r   r   s    r   test_grade_D_at_60z'TestGradeCalculation.test_grade_D_at_60*   r   r   c                 8    t        j                  d      dk(  sJ y )N;   Fr   r   s    r   test_grade_F_at_59z'TestGradeCalculation.test_grade_F_at_59-   r   r   c                 8    t        j                  d      dk(  sJ y )Nr   r.   r   r   s    r   test_grade_F_at_0z&TestGradeCalculation.test_grade_F_at_00   s      #s***r   N)__name__
__module____qualname____doc__r   r   r   r   r!   r$   r(   r+   r/   r1    r   r   r   r      s7    ,-,,,,,,,+r   r   c                   "    e Zd ZdZd Zd Zd Zy)TestWeightedScorez!Test weighted average calculationc                 l    ddiddiddiddiddiddiddid}t        j                  |      }|dk(  sJ y )Nscorer   test_pass_ratepyright_errorscode_coverage	tech_debtsecuritydocumentationdeploy_stability      Y@r   calculate_weighted_scorer   
categoriesr:   s      r   test_weighted_score_all_100z-TestWeightedScore.test_weighted_score_all_1007   sX    &n&n%s^!3 #%s^!(#

 ++J7~~r   c                 l    ddiddiddiddiddiddiddid}t        j                  |      }|dk(  sJ y )Nr:   r   r;           rD   rF   s      r   test_weighted_score_all_zeroz.TestWeightedScore.test_weighted_score_all_zeroD   sX    &l&l%q\!1 !%q\!(!

 ++J7||r   c                     ddiddiddiddiddiddiddid}t        j                  |      }t        |dz
        dk  sJ y )Nr:   r   r   2   r;   g     @J@g{Gz?)r   rE   absrF   s      r   test_weighted_score_mixedz+TestWeightedScore.test_weighted_score_mixedQ   sg      'n&l%r]!2 "%r]!("

 ++J7 54< 4'''r   N)r2   r3   r4   r5   rH   rK   rO   r6   r   r   r8   r8   4   s    +(r   r8   c                   (    e Zd ZdZd Zd Zd Zd Zy)TestOutputSchemazTest JSON output schemac                     t        j                  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|v sJ d|v sJ d|v sJ y )	Nr    r:   detailsr;   rG   baselinefix_pct_resultr:   graderG   r   build_resultr   results     r   test_output_has_scorez&TestOutputSchema.test_output_has_scoree   s    ,.2">,.2">+-"!=')b9&(R8+-"!=.0R$@ 
 &   &   v%%%r   c                     ddddd}t        j                  dddddddddddddddddddddd	d |
      }d|v sJ |d   d   dk(  sJ |d   d   dk(  sJ y )N
            >@F)total	fix_countpctwarningr   rS   rT   r;   rV   fix_pctrc   rd   rZ   )r   rg   r]   s      r   test_output_has_fix_pct_sectionz0TestOutputSchema.test_output_has_fix_pct_sectionw   s    QtN,.2">,.2">+-"!=')b9&(R8+-"!=.0R$@ "
 F"""i )R///i -222r   c                     t        j                  ddddddddddddddddddddddd d       }t        |d   t              sJ y )NU   rS   rT   r;   rV   r:   )r   r[   
isinstanceintr\   s     r   test_output_score_is_intz)TestOutputSchema.test_output_score_is_int   sk    ,.2">,.2">+-"!=')b9&(R8+-"!=.0R$@ 
 &/3///r   c                     t        j                  ddddddddddddddddddddddd d       }t        j                  |      }t        j                  |      }|d   |d   k(  sJ y )Nr   okrT   r;   rV   r:   )r   r[   jsondumpsloads)r   r]   json_strparseds       r    test_output_is_json_serializablez1TestOutputSchema.test_output_is_json_serializable   s    ,.4"@,.4"@+-$!?')d;&(T:+-$!?.0T$B 
 ::f%H%g&/111r   N)r2   r3   r4   r5   r^   rh   rm   ru   r6   r   r   rQ   rQ   b   s    !&$3&0 2r   rQ   c                   4    e Zd ZdZd Zd Zd Zd Zd Zd Z	y)	TestBaselineComparisonzTest baseline comparison logicc           	          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ddiddiddiddiddiddidi}t        j                  ||d 	      }|d   d
   }|d   dk(  sJ |d   dk(  sJ y )Nr	   rS   rT   r   r#   r;   rG   r:   rW   rX   r<   deltar`   	directionimprovedrZ   r   current_categoriesrW   r]   cats        r   !test_baseline_comparison_improvedz8TestBaselineComparison.test_baseline_comparison_improved   s    (*r:(*r:')b9#%"5"$4')b9*, <
 #*B-#*B-")2%r]$bM")2%,bM

 !3hW[\\"#347|r!!!;:---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iddiddiddiddiddiddidi}t        j                  ||d       }|d   d	   }|d
   dk(  sJ |d   dk(  sJ y )Nr#   rS   rT   r   r;   rG   r:   ry   r<   rz   ir{   degradedrZ   r}   s        r   !test_baseline_comparison_degradedz8TestBaselineComparison.test_baseline_comparison_degraded   s    (*r:(*r:')b9#%"5"$4')b9*, <
 #*B-#*B-")2%r]$bM")2%,bM

 !3hW[\\"#347|s""";:---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iddiddiddiddiddiddidi}t        j                  ||d       }|d   d	   }|d
   dk(  sJ |d   dk(  sJ y )Nr   rS   rT   r#   r;   rG   r:   ry   r<   rz   r   r{   stablerZ   r}   s        r   test_baseline_comparison_stablez6TestBaselineComparison.test_baseline_comparison_stable   s    (*r:(*r:')b9#%"5"$4')b9*, <
 #*B-#*B-")2%r]$bM")2%,bM

 !3hW[\\"#347|q   ;8+++r   c                     t        j                  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	|vsJ d
|vsJ y)z9When baseline file doesn't exist, no comparison, no errorr   rS   rT   r;   NrV   rG   r<   rz   r{   rZ   )r   r]   r   s      r   #test_baseline_file_missing_gracefulz:TestBaselineComparison.test_baseline_file_missing_graceful   s    ,.2">,.2">+-"!=')b9&(R8+-"!=.0R$@ 
 \"#34c!!!#%%%r   c                 6    t        j                  d      }|J y)z6load_baseline returns None for missing file gracefullyz"/nonexistent/path/qa-baseline.jsonN)r   load_baseliner\   s     r   test_load_baseline_missing_filez6TestBaselineComparison.test_load_baseline_missing_file  s    !!"FG~~r   c                 
   t        j                  ddd      5 }t        j                  di d|       |j	                          t        j                  |j                        }ddd       J |d   dk(  sJ y# 1 sw Y   xY w)	z+load_baseline reads JSON from existing filew.jsonFmodesuffixdeleterj   )r:   rG   Nr:   )tempfileNamedTemporaryFilerp   dumpflushr   r   name)r   fr]   s      r   test_load_baseline_valid_filez4TestBaselineComparison.test_load_baseline_valid_file  s|    ((c'%P 	.TUII"5q9GGI%%aff-F	. !!!g"$$$	. 	.s   A	A99BN)
r2   r3   r4   r5   r   r   r   r   r   r   r6   r   r   rw   rw      s#    (.4.4,4&(
%r   rw   c                   L    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)
TestFixPctzTest fix percentage calculationc                     ddddddddd}t        j                  |      }|d   d	k(  sJ |d
   dk(  sJ |d   dk(  sJ |d   du sJ y )Ntask-1u   새 기능 추가	completedtask_iddescriptionstatustask-2u   리팩토링r   r   rc      rd   r   re   rJ   rf   Fr   calculate_fix_pctr   tasksr]   s      r   test_fix_pct_no_fix_tasksz$TestFixPct.test_fix_pct_no_fix_tasks%  s|    "*;NZef"*>U`a
 %%e,g!###k"a'''e}###i E)))r   c                     ddddddddd}t        j                  |      }|d   d	k(  sJ |d
   d	k(  sJ |d   dk(  sJ |d   du sJ y )Nr   u   버그 수정 작업r   r   r   zfix login errorr   rc   r   rd   re   rC   rf   Tr   r   s      r   test_fix_pct_all_fix_tasksz%TestFixPct.test_fix_pct_all_fix_tasks0  s}    "*;Q]hi"*;LXcd
 %%e,g!###k"a'''e}%%%i D(((r   c                     i }t        d      D ]  }d| ddd|d| <    t        dd      D ]  }d| ddd|d| <    t        j                  |      }|d   dk(  sJ |d	   d
k(  sJ |d   dk(  sJ |d   du sJ y)z31% should trigger warningr&   task-   일반 작업r   r   r   fix somethingrc   rd      re   g      ?@rf   TNranger   r   r   r   ir]   s       r   $test_fix_pct_30pct_threshold_warningz/TestFixPct.test_fix_pct_30pct_threshold_warning;  s    r 	qA/4QC[do!pEE!+	qr3 	qA/4QC[do!pEE!+	q%%e,g#%%%k"b(((e}$$$i D(((r   c                     i }t        d      D ]  }d| ddd|d| <    t        dd      D ]  }d| ddd|d| <    t        j                  |      }|d   dk(  sJ |d	   d
k(  sJ |d   dk(  sJ |d   du sJ y)z&Exactly 30% should NOT trigger warningr#   r   r   r   r   r   r   rc   rd      re   rb   rf   FNr   r   s       r   #test_fix_pct_30pct_exact_no_warningz.TestFixPct.test_fix_pct_30pct_exact_no_warningH  s    r 	qA/4QC[do!pEE!+	qr3 	qA/4QC[do!pEE!+	q%%e,g#%%%k"b(((e}$$$i E)))r   c                 R    dddddi}t        j                  |      }|d   dk(  sJ y )Nt1zfix the broken pipeliner   r   rd      r   r   s      r   test_fix_pct_keywords_fixz$TestFixPct.test_fix_pct_keywords_fixU  s8    48Q]hij%%e,k"a'''r   c                 R    dddddi}t        j                  |      }|d   dk(  sJ y )Nr   u   코드 수정 필요r   r   rd   r   r   r   s      r      test_fix_pct_keywords_수정u'   TestFixPct.test_fix_pct_keywords_수정Z  s8    48NZefg%%e,k"a'''r   c                 R    dddddi}t        j                  |      }|d   dk(  sJ y )Nr   u   버그 발견 및 처리r   r   rd   r   r   r   s      r      test_fix_pct_keywords_버그u'   TestFixPct.test_fix_pct_keywords_버그_  s8    48R^ijk%%e,k"a'''r   c                 |    t        j                  i       }|d   dk(  sJ |d   dk(  sJ |d   dk(  sJ |d   du sJ y)	z/Empty tasks dict should return pct=0 gracefullyrc   r   rd   re   rJ   rf   FNr   r\   s     r   test_fix_pct_empty_tasksz#TestFixPct.test_fix_pct_empty_tasksd  s\    %%b)g!###k"a'''e}###i E)))r   c                 <    t        j                  d      }|i k(  sJ y)z?load_task_timers returns empty dict for missing file gracefullyz/nonexistent/task-timers.jsonN)r   load_task_timersr\   s     r   "test_load_task_timers_missing_filez-TestFixPct.test_load_task_timers_missing_filel  s    $$%DE||r   c                 "   ddddddii}t        j                  ddd	      5 }t        j                  ||       |j	                          t        j                  |j                        }d
d
d
       dv sJ |d   d   dk(  sJ y
# 1 sw Y   xY w)z1load_task_timers reads tasks from valid JSON filer   r   z	test taskr   r   r   r   Fr   Nr   )r   r   rp   r   r   r   r   r   )r   datar   r]   s       r    test_load_task_timers_valid_filez+TestFixPct.test_load_task_timers_valid_fileq  s     h{Vab

 ((c'%P 	1TUIIdAGGI((0F	1 6!!!h.+===	1 	1s   ABBN)r2   r3   r4   r5   r   r   r   r   r   r   r   r   r   r   r6   r   r   r   r   "  s7    )	*	))*(
(
(
*
>r   r   c                   F    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zy)TestCollectorFunctionsz!Test category collector functionsc                     t        j                         5 }t        j                  |      }d|v sJ d|v sJ d|d   cxk  rdk  sJ  J 	 ddd       y# 1 sw Y   yxY w)z6Each collector must return dict with score and detailsr:   rU   r   r   Nr   TemporaryDirectoryr   collect_test_pass_rater   tmpdirr]   s      r   &test_collect_returns_score_and_detailsz=TestCollectorFunctions.test_collect_returns_score_and_details  sn    ((* 	/f..v6Ff$$$&&&w.3.....		/ 	/ 	/   5AAc                     t        j                         5 }t        j                  |      }d|v sJ d|v sJ d|d   cxk  rdk  sJ  J 	 d d d        y # 1 sw Y   y xY wNr:   rU   r   r   )r   r   r   collect_pyright_errorsr   s      r   5test_collect_pyright_errors_returns_score_and_detailszLTestCollectorFunctions.test_collect_pyright_errors_returns_score_and_details  sn    ((* 	/f..v6Ff$$$&&&w.3.....		/ 	/ 	/r   c                     t        j                         5 }t        j                  |      }d|v sJ d|v sJ d|d   cxk  rdk  sJ  J 	 d d d        y # 1 sw Y   y xY wr   )r   r   r   collect_code_coverager   s      r   4test_collect_code_coverage_returns_score_and_detailszKTestCollectorFunctions.test_collect_code_coverage_returns_score_and_details  n    ((* 	/f--f5Ff$$$&&&w.3.....		/ 	/ 	/r   c                     t        j                         5 }t        j                  |      }d|v sJ d|v sJ d|d   cxk  rdk  sJ  J 	 d d d        y # 1 sw Y   y xY wr   )r   r   r   collect_tech_debtr   s      r   0test_collect_tech_debt_returns_score_and_detailszGTestCollectorFunctions.test_collect_tech_debt_returns_score_and_details  sn    ((* 	/f))&1Ff$$$&&&w.3.....		/ 	/ 	/r   c                     t        j                         5 }t        j                  |      }d|v sJ d|v sJ d|d   cxk  rdk  sJ  J 	 d d d        y # 1 sw Y   y xY wr   )r   r   r   collect_securityr   s      r   /test_collect_security_returns_score_and_detailszFTestCollectorFunctions.test_collect_security_returns_score_and_details  sn    ((* 	/f((0Ff$$$&&&w.3.....		/ 	/ 	/r   c                     t        j                         5 }t        j                  |      }d|v sJ d|v sJ d|d   cxk  rdk  sJ  J 	 d d d        y # 1 sw Y   y xY wr   )r   r   r   collect_documentationr   s      r   4test_collect_documentation_returns_score_and_detailszKTestCollectorFunctions.test_collect_documentation_returns_score_and_details  r   r   c                     t        j                         5 }t        j                  |      }d|v sJ d|v sJ d|d   cxk  rdk  sJ  J 	 d d d        y # 1 sw Y   y xY wr   )r   r   r   collect_deploy_stabilityr   s      r   7test_collect_deploy_stability_returns_score_and_detailszNTestCollectorFunctions.test_collect_deploy_stability_returns_score_and_details  sn    ((* 	/f008Ff$$$&&&w.3.....		/ 	/ 	/r   c                     t        j                         5 }t        j                  |      }|d   dk(  sJ |d   dk7  sJ 	 ddd       y# 1 sw Y   yxY w)z0Empty directory should return score=0 gracefullyr:   r   rU   rS   Nr   r   s      r   %test_collect_test_pass_rate_empty_dirz<TestCollectorFunctions.test_collect_test_pass_rate_empty_dir  sZ    ((* 	+f..v6F'?a''')$***	+ 	+ 	+s   *A		Ac                     t        j                         5 }t        j                  |      }h d}t	        |j                               |k(  sJ 	 ddd       y# 1 sw Y   yxY w)z/collect_all_categories returns all 7 categories>   r@   r?   r>   rA   r=   r<   rB   N)r   r   r   collect_all_categoriessetkeys)r   r   rG   expected_keyss       r   test_collect_all_categoriesz2TestCollectorFunctions.test_collect_all_categories  sX    ((* 	;f226:JM z()]:::	; 	; 	;s   8AA N)r2   r3   r4   r5   r   r   r   r   r   r   r   r   r   r6   r   r   r   r     s2    +///////+;r   r   )r5   rp   sysr   pathlibr   unittest.mockr   r   pytestpathinsertstr__file__parenthealth_scorer   r   r8   rQ   rw   r   r   r6   r   r   <module>r      s    F  
   *  3tH~,,334 5 + +D+( +(\I2 I2Xq% q%h[> [>|I; I;r   