1+ from unittest .mock import ANY , MagicMock
2+
13import numpy as np
24import pytest
35
46
5- class FakeTk :
6- def __init__ (self ):
7- self .titles = []
8- self .updated = 0
9- self .destroyed = False
10-
11- def title (self , text ):
12- self .titles .append (text )
13-
14- def update (self ):
15- self .updated += 1
16-
17- def destroy (self ):
18- self .destroyed = True
19-
20-
21- class FakeLabel :
22- def __init__ (self , window ):
23- self .window = window
24- self .packed = False
25- self .configured = {}
26-
27- def pack (self ):
28- self .packed = True
29-
30- def configure (self , ** kwargs ):
31- self .configured .update (kwargs )
32-
33-
34- class FakePhotoImage :
35- def __init__ (self , image = None , master = None ):
36- self .image = image
37- self .master = master
38-
39-
407def test_display_init_raises_when_tk_unavailable (monkeypatch ):
418 import dlclive .display as display_mod
429
@@ -47,52 +14,66 @@ def test_display_init_raises_when_tk_unavailable(monkeypatch):
4714
4815
4916def test_display_frame_creates_window_and_updates (headless_display_env ):
50- display_mod = headless_display_env
17+ env = headless_display_env
18+ display_mod = env .mod
5119 disp = display_mod .Display (radius = 3 , pcutoff = 0.5 )
5220
5321 frame = np .zeros ((100 , 120 , 3 ), dtype = np .uint8 )
5422 pose = np .array ([[[10 , 10 , 0.9 ], [50 , 50 , 0.2 ]]]) # 1 animal, 2 bodyparts
5523
5624 disp .display_frame (frame , pose )
5725
58- assert disp .window is not None
59- assert disp .lab is not None
60- assert disp .lab .packed is True
61- assert disp .window .updated == 1
62- assert "image" in disp .lab .configured # configured with PhotoImage
26+ # Window created and initialized
27+ env .tk_ctor .assert_called_once_with ()
28+ env .tk .title .assert_called_once_with ("DLC Live" )
29+
30+ # Label created and packed
31+ env .label_ctor .assert_called_once_with (env .tk )
32+ env .label .pack .assert_called_once ()
33+
34+ # PhotoImage created with correct master + image passed
35+ env .photo_ctor .assert_called_once_with (image = ANY , master = env .tk )
36+
37+ # Image configured on label and window updated
38+ env .label .configure .assert_called_once_with (image = env .photo )
39+ env .tk .update .assert_called_once_with ()
6340
6441
6542def test_display_draws_only_points_above_cutoff (headless_display_env , monkeypatch ):
66- display_mod = headless_display_env
43+ env = headless_display_env
44+ display_mod = env .mod
6745 disp = display_mod .Display (radius = 3 , pcutoff = 0.5 )
6846
47+ # Patch colormap so color sampling is deterministic and always long enough
48+ class FakeCC :
49+ bmy = [(1 , 0 , 0 ), (0 , 1 , 0 ), (0 , 0 , 1 ), (1 , 1 , 0 )]
50+
51+ monkeypatch .setattr (display_mod , "cc" , FakeCC )
52+
6953 frame = np .zeros ((100 , 100 , 3 ), dtype = np .uint8 )
7054 pose = np .array (
7155 [
7256 [
7357 [10 , 10 , 0.9 ], # draw
7458 [20 , 20 , 0.49 ], # don't draw
75- [30 , 30 , 0.5001 ], # draw (>= )
59+ [30 , 30 , 0.5001 ], # draw (> pcutoff )
7660 ]
7761 ],
7862 dtype = float ,
7963 )
8064
81- ellipses = []
82-
83- class DrawRecorder :
84- def ellipse (self , coords , fill = None , outline = None ):
85- ellipses .append ((coords , fill , outline ))
86-
87- monkeypatch .setattr (display_mod .ImageDraw , "Draw" , lambda img : DrawRecorder ())
65+ draw = MagicMock (name = "DrawInstance" )
66+ monkeypatch .setattr (display_mod .ImageDraw , "Draw" , MagicMock (return_value = draw ))
8867
8968 disp .display_frame (frame , pose )
9069
91- assert len (ellipses ) == 2
70+ # Two points above cutoff => two ellipse calls
71+ assert draw .ellipse .call_count == 2
9272
9373
9474def test_destroy_calls_window_destroy (headless_display_env ):
95- display_mod = headless_display_env
75+ env = headless_display_env
76+ display_mod = env .mod
9677 disp = display_mod .Display ()
9778
9879 frame = np .zeros ((10 , 10 , 3 ), dtype = np .uint8 )
@@ -101,13 +82,13 @@ def test_destroy_calls_window_destroy(headless_display_env):
10182 disp .display_frame (frame , pose )
10283 disp .destroy ()
10384
104- assert disp . window . destroyed is True
85+ env . tk . destroy . assert_called_once_with ()
10586
10687
10788def test_set_display_color_sampling_safe (headless_display_env , monkeypatch ):
108- display_mod = headless_display_env
89+ env = headless_display_env
90+ display_mod = env .mod
10991
110- # Provide a fixed colormap list
11192 class FakeCC :
11293 bmy = [(1 , 0 , 0 ), (0 , 1 , 0 ), (0 , 0 , 1 ), (1 , 1 , 0 ), (0 , 1 , 1 ), (1 , 0 , 1 )]
11394
@@ -118,3 +99,9 @@ class FakeCC:
11899
119100 assert disp .colors is not None
120101 assert len (disp .colors ) >= 3
102+
103+ # Also verify window setup calls happened
104+ env .tk_ctor .assert_called_once_with ()
105+ env .tk .title .assert_called_once_with ("DLC Live" )
106+ env .label_ctor .assert_called_once_with (env .tk )
107+ env .label .pack .assert_called_once ()
0 commit comments