89 lines
4.3 KiB
Python
89 lines
4.3 KiB
Python
"""Run: PYTHONPATH=app pytest -q tests/test_calendar.py"""
|
||
from datetime import date, datetime, timedelta
|
||
from zoneinfo import ZoneInfo
|
||
import pytest
|
||
from services import ha_views, alfred_intents as intents
|
||
|
||
PARIS=ZoneInfo('Europe/Paris')
|
||
NOW=datetime(2026,10,25,18,0,tzinfo=PARIS)
|
||
|
||
@pytest.mark.parametrize('utterance,start,end',[
|
||
('J’ai quelque chose de prévu demain ?',date(2026,10,26),date(2026,10,27)),
|
||
('Montre mon planning sur 3 jours',date(2026,10,25),date(2026,10,28)),
|
||
('Que j’ai le 8 novembre ?',date(2026,11,8),date(2026,11,9)),
|
||
('Je veux mon agenda du mois',date(2026,10,1),date(2026,11,1)),
|
||
('Qu’est-ce que j’ai ce matin ?',date(2026,10,25),date(2026,10,25)),
|
||
])
|
||
def test_voice_period(utterance,start,end):
|
||
a,b,view=intents.period(utterance,NOW)
|
||
assert a.date()==start
|
||
if 'matin' not in utterance:assert b.date()==end
|
||
else:assert (a.hour,b.hour)==(6,12)
|
||
|
||
@pytest.mark.parametrize('utterance,kind',[
|
||
('Montre mon planning sur 7 jours','calendar'),
|
||
('J’ai des choses de prévu le 8 novembre ?','calendar'),
|
||
('Ajoute un rendez-vous dentiste demain à 15h','create'),
|
||
('Supprime mon rendez-vous demain','delete'),
|
||
('Affiche les caméras extérieures','cameras'),
|
||
('Montre les températures','temperatures'),
|
||
('Reviens à l’accueil','home'),
|
||
('Génère-moi une image de poulet',None),
|
||
])
|
||
def test_intent(utterance,kind):
|
||
result=intents.classify(utterance)
|
||
assert (result or {}).get('kind')==kind
|
||
|
||
|
||
def test_event_adapter(monkeypatch):
|
||
def fake_request(method,path,**kwargs):
|
||
if path=='/api/calendars':return [{'entity_id':'calendar.family','name':'Famille'}]
|
||
if path=='/api/states':return [{'entity_id':'calendar.family','attributes':{'supported_features':3}}]
|
||
if path.startswith('/api/calendars/'):
|
||
return [{'summary':'Dentiste','uid':'abc123','start':{'dateTime':'2026-10-25T10:00:00+01:00'},
|
||
'end':{'dateTime':'2026-10-25T11:00:00+01:00'}}]
|
||
monkeypatch.setattr(ha_views,'_request',fake_request)
|
||
data=ha_views.get_events(datetime(2026,10,25,tzinfo=PARIS),datetime(2026,10,26,tzinfo=PARIS))
|
||
assert data['events'][0]['title']=='Dentiste'
|
||
assert data['events'][0]['id']=='abc123'
|
||
assert data['events'][0]['can_delete'] is True
|
||
|
||
|
||
def test_recurring_no_uid_cannot_delete(monkeypatch):
|
||
def fake_request(method,path,**kwargs):
|
||
if path=='/api/calendars':return [{'entity_id':'calendar.a','name':'A'}]
|
||
if path=='/api/states':return [{'entity_id':'calendar.a','attributes':{'supported_features':0}}]
|
||
if path.startswith('/api/calendars/'):
|
||
return [{'summary':'Test','start':'2026-10-26','end':'2026-10-27'}]
|
||
monkeypatch.setattr(ha_views,'_request',fake_request)
|
||
data=ha_views.get_events(datetime(2026,10,25,tzinfo=PARIS),datetime(2026,10,27,tzinfo=PARIS))
|
||
assert data['events'][0]['all_day'] is True
|
||
assert data['events'][0]['can_delete'] is False
|
||
|
||
|
||
def test_create_event_calls_service(monkeypatch):
|
||
calls=[]
|
||
monkeypatch.setattr(ha_views,'list_calendars',lambda:[{'entity_id':'calendar.family','can_create':True,'can_delete':True}])
|
||
monkeypatch.setattr(ha_views,'_request',lambda method,path,**kwargs:calls.append((method,path,kwargs)) or None)
|
||
start=datetime(2026,11,8,15,0,tzinfo=PARIS)
|
||
assert ha_views.create_event('calendar.family','Dentiste',start,start+timedelta(hours=1))['ok']
|
||
assert calls[0][1]=='/api/services/calendar/create_event'
|
||
assert calls[0][2]['payload']['entity_id']=='calendar.family'
|
||
|
||
|
||
def test_delete_uses_websocket(monkeypatch):
|
||
import websocket
|
||
monkeypatch.setattr(ha_views,'list_calendars',lambda:[{'entity_id':'calendar.family','can_create':True,'can_delete':True}])
|
||
monkeypatch.setattr(ha_views,'_cfg',lambda:('http://ha.example:8123','test-token'))
|
||
class FakeWS:
|
||
messages=[]
|
||
def __init__(self):self.replies=iter(['{"type":"auth_required"}','{"type":"auth_ok"}','{"id":1,"success":true}'])
|
||
def recv(self):return next(self.replies)
|
||
def send(self,m):self.messages.append(m)
|
||
def close(self):pass
|
||
ws=FakeWS()
|
||
monkeypatch.setattr(websocket,'create_connection',lambda url,timeout:ws)
|
||
ha_views.delete_event('calendar.family','event1')
|
||
assert 'calendar/event/delete' in ws.messages[1]
|
||
assert 'event1' in ws.messages[1]
|