
    [i6                         d Z ddlZddlmc mZ ddlmZ ddl	m
Z
mZ ddlZddlmZ ddlmZ ddd	d
ddddddddgdddddd	dddddddg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gdd$d%dd	d&dddgd	d%dd'gd(Zddd)d
ddddgdd$gd)d%dd'gd(Zej        d*efd+            Z G d, d-          ZdS ).z
Unit tests for Garmin Lifestyle Logging feature.

Tests the parsing logic in GarminHealthClient.fetch_lifestyle_logging()
against realistic mock API responses based on actual Garmin API output.
    N)date)	MagicMockpatch)LifestyleLoggingData)GarminHealthClient   QUANTITYz
2026-03-01Alcohol	LIFESTYLE   WINE)	subTypeIdsubTypeNameamountBEER)r   r   YESF)behaviourIdmeasurementTypecalendarDatenamecategorydetails	logStatussleepRelatedzMorning CaffeineCOFFEE)r   r   r   r   r   r   r   r      NONEzLight Exercise)r   r   r   r   r   r   r      zHealthy Meals   zHeavy Meals)r   r   r   r   r   r      z
Late Meals*   zLate Caffeine)r   r   r   r   r   r   r      zIntermittent Fasting)r   totalTrackingcompletedTracking)dailyLogsReportcompletionStatsz
2026-03-02returnc                      t          j        t          dd           5  t          j        t                    } t	                      | _        d| _        | cddd           S # 1 swxY w Y   dS )z1Return a GarminHealthClient with auth mocked out.__init__c                     d S )N )selfkws     5/root/projects/butler/tests/test_lifestyle_logging.py<lambda>zclient.<locals>.<lambda>   s         TN)r   objectr   __new__r   client_authenticated)cs    r.   r3   r3   |   s     
(*6M6M	N	N  &'9::;;	                 s   5AA#&A#c                       e Zd ZdZdeddfdZdeddfdZdeddfdZdeddfdZdeddfd	Z	deddfd
Z
deddfdZdeddfdZdS )TestFetchLifestyleLoggingz0Tests for fetch_lifestyle_logging parsing logic.r3   r'   Nc           	      	   t          j        |dt                    5  t          j        |d          5  |                    t	          ddd                    }ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   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}}|j        }d}||u }|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}||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}||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}||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}||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}}dS )zDAlcohol with logStatus=YES and WINE amount=2 should parse correctly._retry_api_callreturn_value_ensure_authenticated  r   r   Nis notz%(py0)s is not %(py3)sresultpy0py3assert %(py5)spy5Tis)z6%(py2)s
{%(py2)s = %(py0)s.alcohol_logged
} is %(py5)srC   py2rF   assert %(py7)spy7r   ==)z4%(py2)s
{%(py2)s = %(py0)s.alcohol_wine
} == %(py5)sr   )z4%(py2)s
{%(py2)s = %(py0)s.alcohol_beer
} == %(py5)s)z6%(py2)s
{%(py2)s = %(py0)s.alcohol_spirit
} == %(py5)s)z5%(py2)s
{%(py2)s = %(py0)s.alcohol_other
} == %(py5)s)r   r1   MOCK_RESPONSE_WITH_LOGSfetch_lifestyle_loggingr   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanationalcohol_loggedalcohol_winealcohol_beeralcohol_spiritalcohol_other
r,   r3   rA   @py_assert2@py_assert1@py_format4@py_format6@py_assert4@py_assert3@py_format8s
             r.   test_parses_alcohol_quantityz6TestFetchLifestyleLogging.test_parses_alcohol_quantity   sH   \&"3BYZZZ 	J 	Jf&=>> J J77T1a8H8HIIJ J J J J J J J J J J J J J J	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J "!vT!!!!!!!!!!vT!!!!!!!!!!!!v!!!!!v!!!!!!T!!!!!!!!!!!!!!!!!!!!!!!!!$,,$,,,,,,,,,,$,,,,,,,,,,,,v,,,,,v,,,,,,$,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"'a'"a''''''''''"a''''''''''''v'''''v''''''"''''a'''''''''''''''''''''''''''"'a'"a''''''''''"a''''''''''''v'''''v''''''"''''a'''''''''''''''''''''''''''$))$))))))))))$))))))))))))v)))))v))))))$)))))))))))))))))))))))))))))))#(q(#q((((((((((#q((((((((((((v(((((v((((((#((((q(((((((((((((((((((((((((((((4   A;%A$A;$A(	(A;+A(	,A;;A?A?c           	         t          j        |dt                    5  t          j        |d          5  |                    t	          ddd                    }ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   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}}|j        }d}||u }|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}||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}||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}}dS )z6Morning caffeine with coffee=1 should parse correctly.r9   r:   r<   r=   r   r   Nr>   r@   rA   rB   rE   rF   TrG   )z?%(py2)s
{%(py2)s = %(py0)s.morning_caffeine_logged
} is %(py5)srI   rK   rL   rM   )z?%(py2)s
{%(py2)s = %(py0)s.morning_caffeine_coffee
} == %(py5)sr   )z<%(py2)s
{%(py2)s = %(py0)s.morning_caffeine_tea
} == %(py5)s)r   r1   rO   rP   r   rQ   rR   rS   rT   rU   rV   rW   rX   morning_caffeine_loggedmorning_caffeine_coffeemorning_caffeine_tear^   s
             r.   test_parses_morning_caffeinez6TestFetchLifestyleLogging.test_parses_morning_caffeine   s   \&"3BYZZZ 	J 	Jf&=>> J J77T1a8H8HIIJ J J J J J J J J J J J J J J	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J "!vT!!!!!!!!!!vT!!!!!!!!!!!!v!!!!!v!!!!!!T!!!!!!!!!!!!!!!!!!!!!!!!!-55-5555555555-555555555555v55555v555555-5555555555555555555555555555555-22-2222222222-222222222222v22222v222222-2222222222222222222222222222222*/a/*a//////////*a////////////v/////v//////*////a/////////////////////////////rg   c           	      	   t          j        |dt                    5  t          j        |d          5  |                    t	          ddd                    }ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   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}}|j        }d}||u }|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}||u }|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}||u }|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}||u }|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}||u }|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}}dS )zDNONE-type behaviors with logStatus=YES should be True; others False.r9   r:   r<   r=   r   r   Nr>   r@   rA   rB   rE   rF   TrG   )z6%(py2)s
{%(py2)s = %(py0)s.light_exercise
} is %(py5)srI   rK   rL   )z5%(py2)s
{%(py2)s = %(py0)s.healthy_meals
} is %(py5)sF)z3%(py2)s
{%(py2)s = %(py0)s.heavy_meals
} is %(py5)s)z2%(py2)s
{%(py2)s = %(py0)s.late_meals
} is %(py5)s)z<%(py2)s
{%(py2)s = %(py0)s.intermittent_fasting
} is %(py5)s)r   r1   rO   rP   r   rQ   rR   rS   rT   rU   rV   rW   rX   light_exercisehealthy_mealsheavy_meals
late_mealsintermittent_fastingr^   s
             r.   test_parses_boolean_behaviorsz7TestFetchLifestyleLogging.test_parses_boolean_behaviors   sH   \&"3BYZZZ 	J 	Jf&=>> J J77T1a8H8HIIJ J J J J J J J J J J J J J J	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J "!vT!!!!!!!!!!vT!!!!!!!!!!!!v!!!!!v!!!!!!T!!!!!!!!!!!!!!!!!!!!!!!!!$,,$,,,,,,,,,,$,,,,,,,,,,,,v,,,,,v,,,,,,$,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#+t+#t++++++++++#t++++++++++++v+++++v++++++#++++t+++++++++++++++++++++++++++!*U*!U**********!U************v*****v******!****U*************************** )E) E)))))))))) E))))))))))))v)))))v)))))) ))))E)))))))))))))))))))))))))))*3e3*e3333333333*e333333333333v33333v333333*3333e33333333333333333333333333333rg   c           	      V   t          j        |dt                    5  t          j        |d          5  |                    t	          ddd                    }ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   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}}|j        }d}||u }|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}||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}}dS )z9Late Caffeine without logStatus=YES should not be logged.r9   r:   r<   r=   r   r   Nr>   r@   rA   rB   rE   rF   FrG   )z<%(py2)s
{%(py2)s = %(py0)s.late_caffeine_logged
} is %(py5)srI   rK   rL   r   rM   )z<%(py2)s
{%(py2)s = %(py0)s.late_caffeine_coffee
} == %(py5)s)r   r1   rO   rP   r   rQ   rR   rS   rT   rU   rV   rW   rX   late_caffeine_loggedlate_caffeine_coffeer^   s
             r.   test_late_caffeine_not_loggedz7TestFetchLifestyleLogging.test_late_caffeine_not_logged   s   \&"3BYZZZ 	J 	Jf&=>> J J77T1a8H8HIIJ J J J J J J J J J J J J J J	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J "!vT!!!!!!!!!!vT!!!!!!!!!!!!v!!!!!v!!!!!!T!!!!!!!!!!!!!!!!!!!!!!!!!*3e3*e3333333333*e333333333333v33333v333333*3333e333333333333333333333333333*/a/*a//////////*a////////////v/////v//////*////a/////////////////////////////rg   c           
         t          j        |dt                    5  t          j        |d          5  |                    t	          ddd                    }ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   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}}|j        }d}d}d}	t	          |||	          }
||
k    }|s+t          j        d|fd||
f          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
        |	          t          j
        |
          dz  }dd|iz  }t          t          j        |                    dx}x}x}x}x}	}
dS )z&Result date must match requested date.r9   r:   r<   r=   r   r   Nr>   r@   rA   rB   rE   rF   rM   )z_%(py2)s
{%(py2)s = %(py0)s.date
} == %(py12)s
{%(py12)s = %(py4)s(%(py6)s, %(py8)s, %(py10)s)
}r   )rC   rJ   py4py6py8py10py12zassert %(py14)spy14)r   r1   rO   rP   r   rQ   rR   rS   rT   rU   rV   rW   rX   )r,   r3   rA   r_   r`   ra   rb   @py_assert5@py_assert7@py_assert9@py_assert11rd   @py_format13@py_format15s                 r.   test_returns_correct_datez3TestFetchLifestyleLogging.test_returns_correct_date   sT   \&"3BYZZZ 	J 	Jf&=>> J J77T1a8H8HIIJ J J J J J J J J J J J J J J	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J "!vT!!!!!!!!!!vT!!!!!!!!!!!!v!!!!!v!!!!!!T!!!!!!!!!!!!!!!!!!!!!!!!!{.4..A.d4A...{...........{.............v.....v......{...........d.....d......4........A........................................rg   c           	      V   t          j        |dt                    5  t          j        |d          5  |                    t	          ddd                    }ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   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S )zFDay with no logged behaviors (no logStatus=YES anywhere) returns None.r9   r:   r<   r=   r   r   NrG   z%(py0)s is %(py3)srA   rB   rE   rF   )r   r1   MOCK_RESPONSE_EMPTY_LOGSrP   r   rQ   rR   rS   rT   rU   rV   rW   rX   r,   r3   rA   r_   r`   ra   rb   s          r.   test_returns_none_when_no_logsz8TestFetchLifestyleLogging.test_returns_none_when_no_logs   s   \&"3BZ[[[ 	J 	Jf&=>> J J77T1a8H8HIIJ J J J J J J J J J J J J J J	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J v~vvvrg   c           	      L   t          j        |dd          5  t          j        |d          5  |                    t          ddd                    }ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   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S )z%None API response should return None.r9   Nr:   r<   r=   r   r   rG   r   rA   rB   rE   rF   )r   r1   rP   r   rQ   rR   rS   rT   rU   rV   rW   rX   r   s          r.   'test_returns_none_on_empty_api_responsezATestFetchLifestyleLogging.test_returns_none_on_empty_api_response   s   \&"3$GGG 	J 	Jf&=>> J J77T1a8H8HIIJ J J J J J J J J J J J J J J	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J v~vvvs4   A6%AA6A#	#A6&A#	'A66A:=A:c           	      N   t          j        |dt                    5  t          j        |d          5  |                    t	          ddd                    }ddd           n# 1 swxY w Y   ddd           n# 1 swxY w Y   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}}|j        }|t          k    }|st          j        d|fd|t          f          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dz  }dd|iz  }	t          t          j        |	                    dx}}dS )z2raw_data field must contain the full API response.r9   r:   r<   r=   r   r   Nr>   r@   rA   rB   rE   rF   rM   )z0%(py2)s
{%(py2)s = %(py0)s.raw_data
} == %(py4)srO   )rC   rJ   ry   zassert %(py6)srz   )r   r1   rO   rP   r   rQ   rR   rS   rT   rU   rV   rW   rX   raw_data)
r,   r3   rA   r_   r`   ra   rb   rd   @py_format5@py_format7s
             r.   test_raw_data_preservedz1TestFetchLifestyleLogging.test_raw_data_preserved   s   \&"3BYZZZ 	J 	Jf&=>> J J77T1a8H8HIIJ J J J J J J J J J J J J J J	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J 	J "!vT!!!!!!!!!!vT!!!!!!!!!!!!v!!!!!v!!!!!!T!!!!!!!!!!!!!!!!!!!!!!!!!9"99999999999"9999999999999v99999v99999999999999999"999999"999999999999999999999999999999rg   )__name__
__module____qualname____doc__r   rf   rl   rs   rw   r   r   r   r   r+   r0   r.   r7   r7      s3       ::)3E )$ ) ) ) )	03E 	0$ 	0 	0 	0 	044F 44 4 4 4 404F 04 0 0 0 0/0B /t / / / /5G D    >P UY    :.@ :T : : : : : :r0   r7   )r   builtinsrS   _pytest.assertion.rewrite	assertionrewriterQ   datetimer   unittest.mockr   r   pytesthealth.models.daily_metricsr   health.services.garmin_clientr   rO   r   fixturer3   r7   r+   r0   r.   <module>r      s                       * * * * * * * *  < < < < < < < < < < < < )(#!DD77 !	
 	
 )(&#AFF "	
 	
 %($#!	
 	
 %(##!	
 	
 %(!#!	
 	
 %( #!	
 	
 )(##99 "
	
 
	
 %(*#!	
 	
QPd &PQRReU U t )(#&'??@!	
 	

 &PQRR  $ "    R: R: R: R: R: R: R: R: R: R:r0   