
    wiy"                    >   d Z ddlmZ ddlZddlmc mZ ddl	Z	ddl
Z
ddlmZ ddlmZ ddlZ ee      j#                         j$                  d   ZeZ ee      e
j,                  vr"e
j,                  j/                  d ee             ddlmZ dddZ G d	 d
      Zy)zTests for FRTemporalAnalyzer.    )annotationsN)Path)	AsyncMock   )FRTemporalAnalyzerc                    | |dS )zBuild a single detection dict.identity
confidence r	   s     S/home/nelsen/Projects/kognitive/orchestrator/src/services/tests/test_fr_analyzer.py_detr      s     
;;    c                     e Zd ZdZej
                  j                  dd       Zej
                  j                  dd       Zej
                  j                  dd       Z	ej
                  j                  dd       Z
ej
                  j                  dd       Zej
                  j                  dd       Zej
                  j                  dd       Zej
                  j                  dd	       Zej
                  j                  dd
       Zej
                  j                  dd       Zej
                  j                  dd       Zy)TestFRTemporalAnalyzerz&Tests for consistency detection logic.c                   K   t               }t        dd      }|j                  |       t        d      D ]*  }|j	                  t        d      gd|z          d{    , |j                          y7 w)	z>Feeding detections for less than threshold_s must NOT trigger.      @      $@consistency_threshold_swindow_s   Alice      Y@	timestampN)r   r   on_consistent_detectionrangefeedr   assert_not_called)selfcallbackanalyzeris       r   test_no_trigger_below_thresholdz6TestFRTemporalAnalyzer.test_no_trigger_below_threshold"   st      ;%cDQ((2 q 	FA--g519-EEE	F 	""$ Fs   AA6A4A6c           	     N  K   t               }t        dd      }|j                  |       t        d      D ]+  }|j	                  t        dd      gd|z          d	{    - |j                          |j                  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}}t         j"                  }d}d} |||      }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nd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}}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	7 ŭw)zCConsistent detections for >= threshold_s MUST trigger the callback.r   r   r      r   g?r   r   Nr   ==)z%(py0)s == %(py3)sr
   )py0py3assert %(py5)spy5g{Gz?)abs)z[%(py0)s == %(py10)s
{%(py10)s = %(py4)s
{%(py4)s = %(py2)s.approx
}(%(py6)s, abs=%(py8)s)
}r   pytest)r*   py2py4py6py8py10zassert %(py12)spy12)>=)z%(py0)s >= %(py3)sduration)r   r   r   r   r   r   assert_called_once	call_args
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationr/   approx)r!   r"   r#   r$   r
   r   r7   @py_assert2@py_assert1@py_format4@py_format6@py_assert3@py_assert5@py_assert7@py_assert9@py_format11@py_format13s                    r   test_trigger_at_thresholdz0TestFRTemporalAnalyzer.test_trigger_at_threshold/   s     ;%cDQ((2 q 	LA--gt!4 5-KKK	L 	##%)1););A)>&*h""x7""""x7""""""x"""x"""7"""""""#]]:4:T:]4T::z:::::z:::::::z:::z::::::V:::V:::]:::4:::T:::::::::::x3x3xx3 Ls   AL%L"KL%c                h  K   t               }t        dd      }|j                  |       t        d      D ]*  }|j	                  t        d      gd|z          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                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}t        dd      D ]*  }|j	                  t        d      gd|z          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                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y7 7 ҭw)z>Same identity must NOT be re-notified after the first trigger.      @r   r      Bobr   r   N   r(   z2%(py2)s
{%(py2)s = %(py0)s.call_count
} == %(py5)sr"   r*   r0   r-   assert %(py7)spy7
   )r   r   r   r   r   r   
call_countr:   r;   r<   r=   r>   r?   r@   rA   	r!   r"   r#   r$   rD   @py_assert4rG   rF   @py_format8s	            r   test_no_re_notificationz.TestFRTemporalAnalyzer.test_no_re_notification@   s     ;%cDQ((2 q 	DA--e-CCC	D ""'a'"a''''"a''''''x'''x'''"'''a''''''' q" 	DA--e-CCC	D ""'a'"a''''"a''''''x'''x'''"'''a''''''' D Ds&   AH2H-D H2H0CH20H2c                  K   t               }t        dd      }|j                  |       t        d      D ]*  }|j	                  t        d      gd|z          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                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|j                  d       t        dd      D ]*  }|j	                  t        d      gd|z          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                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y7 7 ҭw)z8After clear_identity, the same person can trigger again.rO   r   r   rP   Carolr   r   NrR   r(   rS   r"   rT   rU   rV   rW   r   )r   r   r   r   r   r   rX   r:   r;   r<   r=   r>   r?   r@   rA   clear_identityrY   s	            r   )test_re_notification_after_clear_identityz@TestFRTemporalAnalyzer.test_re_notification_after_clear_identityS   s     ;%cDQ((2 q 	FA--g519-EEE	F ""'a'"a''''"a''''''x'''x'''"'''a''''''' 	(q" 	FA--g519-EEE	F ""'a'"a''''"a''''''x'''x'''"'''a''''''' F Fs&   AIH>DI.I/CIIc                  K   t               }t        dd      }|j                  |       t        d      D ]*  }|j	                  t        d      gd|z          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                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|j                          t        d      D ]*  }|j	                  t        d      gd|z          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                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y7 7 ҭw)z3reset() must clear history and notified identities.rO   r   r   rP   Daver   r   NrR   r(   rS   r"   rT   rU   rV      g      i@r   )r   r   r   r   r   r   rX   r:   r;   r<   r=   r>   r?   r@   rA   resetrY   s	            r   test_reset_clears_everythingz3TestFRTemporalAnalyzer.test_reset_clears_everythingg   s     ;%cDQ((2 q 	EA--f%!)-DDD	E ""'a'"a''''"a''''''x'''x'''"'''a''''''' q 	EA--f%!)-DDD	E ""'a'"a''''"a''''''x'''x'''"'''a''''''' E Es&   AIH<DI,H?-CI?Ic                  K   t               }t        dd      }|j                  |       t        d      D ]=  }|dv rt	        d      g}nt	        d      g}|j                  |d|z   	       d
{    ? |j                  D cg c]  }|d   d   dk(  s| }}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}	}|j                  D cg c]  }|d   d   dk(  s| }}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
7 rc c}w c c}w w)zHAn identity must appear in >= 60% of frames to be considered consistent.r   r   r   rW   )r   r      EveFrankr   r   Nr   r(   )z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)slen	eve_calls)r*   py1r+   r2   zassert %(py8)sr3   rR   frank_calls)r   r   r   r   r   r   call_args_listrj   r:   r;   r<   r=   r>   r?   r@   rA   )r!   r"   r#   r$   detscrk   rC   rH   rZ   @py_format7@py_format9rm   s                r   test_presence_ratio_requirementz6TestFRTemporalAnalyzer.test_presence_ratio_requirement|   s     ;%cDQ((2 r 	;AI~U}W--	-:::	;  ..
!A$q'U2BA
	 
 9~""~""""~""""""s"""s""""""9"""9"""~""""""""""  ..
!A$q'W2DA
 
 ;$1$1$$$$1$$$$$$s$$$s$$$$$$;$$$;$$$$$$1$$$$$$$ ;

s>   A-K./K!0K.K$K$D K.9K)
K)DK.$
K.c                  K   t               }t        dd      }|j                  |       t        d      D ]6  }|j	                  t        dd      t        dd      gd	|z   
       d{    8 |j                  D ch c]
  }|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}}y7 qc c}w w)z=Two different identities both consistent should both trigger.rO   r   r   rP   r   g333333?rQ   gffffff?r   r   Nr   )in)z%(py1)s in %(py3)striggered_identities)rl   r+   r,   r-   )r   r   r   r   r   r   rn   r:   r;   r?   r<   r=   r>   r@   rA   )
r!   r"   r#   r$   rp   rv   @py_assert0rC   rE   rF   s
             r   test_multiple_identitiesz/TestFRTemporalAnalyzer.test_multiple_identities   s_     ;%cDQ((2 q 	A--gt$d5$&78!)     	 2:1H1HIA!QII.w.....w....w..................,u,,,,,u,,,,u,,,,,,,,,,,,,,,,,,
  Js%   A&G!(G)G!=GEG!G!c                  K   t               }t        dd      }|j                  |       t        d      D ]#  }|j	                  ddigd|z          d	{    % |j                          |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	7 w)zADetections without an 'identity' key should default to 'unknown'.rO   r   r   rP   r   g      ?r   r   Nr   unknownr(   z%(py1)s == %(py4)srl   r1   assert %(py6)sr2   )r   r   r   r   r   r8   r9   r:   r;   r?   r@   rA   )	r!   r"   r#   r$   rw   rG   rC   @py_format5rq   s	            r   test_unknown_identity_defaultsz5TestFRTemporalAnalyzer.test_unknown_identity_defaults   s      ;%cDQ((2q 	A--$%!)     	 	##%!!!$Q'494'94444'9444'44494444444s   AC<C:B%C<c                   K   t        dd      }t        d      D ]*  }|j                  t        d      gd|z          d{    , y7 w)	z5Feed should not error when no callback is registered.rO   r   r   rP   r   r   r   N)r   r   r   r   )r!   r#   r$   s      r   test_no_callback_registeredz2TestFRTemporalAnalyzer.test_no_callback_registered   sN      &cDQ q 	FA--g519-EEE	FEs   ?AA	Ac                  K   t               }t        dd      }|j                  |       |j                  t	        d      gd       d{    |j                  t	        d      gd       d{    |j                          y7 :7 w)	z5Fewer than MIN_FRAMES in the window must not trigger.g       @r   r   r   r   r   Ng     Y@)r   r   r   r   r   r    )r!   r"   r#   s      r   test_min_frames_requirementz2TestFRTemporalAnalyzer.test_min_frames_requirement   sz      ; &cDQ((2 mmT']Oum===mmT']Oum===""$ 	>=s$   A	B
B$B
0B1B
B
c                l  K   t        dd      }t        d      D ]*  }|j                  t        d      gd|z          d{    , |j                  t        d      gd	       d{    |j                  }t        |      }d
}||k(  }|s
t        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                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}x}}|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7 7 ɭw)z+Entries older than window_s must be pruned.rO   r   r   rP   r   r   r   Ng     [@rR   r(   )zX%(py5)s
{%(py5)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s._detection_history
})
} == %(py8)srj   r#   )r*   rl   r+   r-   r3   zassert %(py10)sr4   r   r{   r|   r}   r2   )r   r   r   r   _detection_historyrj   r:   r;   r<   r=   r>   r?   r@   rA   )r!   r#   r$   rC   rZ   rI   @py_assert6rr   rK   rw   rG   r~   rq   s                r   &test_sliding_window_prunes_old_entriesz=TestFRTemporalAnalyzer.test_sliding_window_prunes_old_entries   s|     &cCP q 	FA--g519-EEE	F mmT']Oum=== ..4s./414/14444/1444444s444s44444484448444.444/44414444444**1-a09E90E99990E9990999E9999999 F 	>s$   ?H4H.&H4(H1)GH41H4N)returnNone)__name__
__module____qualname____doc__r/   markasyncior%   rM   r\   r`   re   rs   rx   r   r   r   r   r   r   r   r   r      sO   0[[
% 
% [[   [[( ($ [[( (& [[( (( [[% %6 [[- -" [[5 5 [[F F [[% % [[: :r   r   )r   gffffff?)r
   strr   floatr   dict)r   
__future__r   builtinsr<   _pytest.assertion.rewrite	assertionrewriter:   r   syspathlibr   unittest.mockr   r/   __file__resolveparentsROOTSRCr   pathinsertservices.fr_analyzerr   r   r   r   r   r   <module>r      s|    # "    
  #  H~''*
s8388HHOOAs3x  3
<B: B:r   