1+ import unittest
2+ from unittest .mock import Mock , MagicMock
3+
4+ from campus_python .api .v1 .timetable import Timetables
5+ from campus_python .interface import ResourceRoot
6+ import campus .model
7+
8+
9+ class TestTimetablesList (unittest .TestCase ):
10+ """Test Timetables.list() method."""
11+
12+ def setUp (self ):
13+ """Set up test fixtures."""
14+ # Create mock client
15+ self .mock_client = Mock ()
16+ self .mock_client .base_url = "https://api.example.com"
17+
18+ # Create resource root
19+ self .root = ResourceRoot (self .mock_client )
20+ self .root .url_prefix = "api/v1"
21+
22+ # Create Timetables instance
23+ self .timetables = Timetables (self .mock_client , root = self .root )
24+
25+ def test_list_without_filters (self ):
26+ """Test list() returns timetables without filters."""
27+ # Mock the response - backend returns direct list
28+ mock_response = Mock ()
29+ mock_response .json .return_value = [
30+ {
31+ "id" : "tt-123" ,
32+ "filename" : "schedule.xlsx" ,
33+ "start_date" : "2026-01-01T00:00:00Z" ,
34+ "end_date" : "2026-06-30T00:00:00Z" ,
35+ "created_at" : "2026-01-01T00:00:00Z"
36+ },
37+ {
38+ "id" : "tt-456" ,
39+ "filename" : "other.xlsx" ,
40+ "start_date" : "2026-07-01T00:00:00Z" ,
41+ "end_date" : "2026-12-31T00:00:00Z" ,
42+ "created_at" : "2026-07-01T00:00:00Z"
43+ }
44+ ]
45+ mock_response .raise_for_status = Mock ()
46+
47+ self .mock_client .get .return_value = mock_response
48+
49+ # Call list()
50+ result = self .timetables .list ()
51+
52+ # Verify the client was called correctly
53+ self .mock_client .get .assert_called_once_with (
54+ "/api/v1/timetable/" ,
55+ query = None
56+ )
57+
58+ # Verify results
59+ self .assertEqual (len (result ), 2 )
60+ self .assertEqual (result [0 ].id , "tt-123" )
61+ self .assertEqual (result [0 ].filename , "schedule.xlsx" )
62+ self .assertEqual (result [1 ].id , "tt-456" )
63+ self .assertEqual (result [1 ].filename , "other.xlsx" )
64+
65+ def test_list_with_filters (self ):
66+ """Test list() with filter parameters."""
67+ # Mock the response - backend returns direct list
68+ mock_response = Mock ()
69+ mock_response .json .return_value = [
70+ {
71+ "id" : "tt-123" ,
72+ "filename" : "schedule.xlsx" ,
73+ "start_date" : "2026-01-01T00:00:00Z" ,
74+ "end_date" : "2026-06-30T00:00:00Z" ,
75+ "created_at" : "2026-01-01T00:00:00Z"
76+ }
77+ ]
78+ mock_response .raise_for_status = Mock ()
79+
80+ self .mock_client .get .return_value = mock_response
81+
82+ # Call list() with filters
83+ result = self .timetables .list (filename = "schedule.xlsx" )
84+
85+ # Verify the client was called with correct filters
86+ self .mock_client .get .assert_called_once_with (
87+ "/api/v1/timetable/" ,
88+ query = {"filename" : "schedule.xlsx" }
89+ )
90+
91+ # Verify results
92+ self .assertEqual (len (result ), 1 )
93+ self .assertEqual (result [0 ].filename , "schedule.xlsx" )
94+
95+ def test_list_empty_result (self ):
96+ """Test list() returns empty list when no timetables found."""
97+ # Mock the response - backend returns direct list
98+ mock_response = Mock ()
99+ mock_response .json .return_value = []
100+ mock_response .raise_for_status = Mock ()
101+
102+ self .mock_client .get .return_value = mock_response
103+
104+ # Call list()
105+ result = self .timetables .list ()
106+
107+ # Verify results
108+ self .assertEqual (len (result ), 0 )
109+
110+ def test_list_with_multiple_filters (self ):
111+ """Test list() with multiple filter parameters."""
112+ # Mock the response - backend returns direct list
113+ mock_response = Mock ()
114+ mock_response .json .return_value = [
115+ {
116+ "id" : "tt-789" ,
117+ "filename" : "test.xlsx" ,
118+ "start_date" : "2026-01-01T00:00:00Z" ,
119+ "end_date" : "2026-06-30T00:00:00Z" ,
120+ "created_at" : "2026-01-01T00:00:00Z"
121+ }
122+ ]
123+ mock_response .raise_for_status = Mock ()
124+
125+ self .mock_client .get .return_value = mock_response
126+
127+ # Call list() with multiple filters
128+ result = self .timetables .list (
129+ filename = "test.xlsx" ,
130+ start_date = "2026-01-01T00:00:00Z"
131+ )
132+
133+ # Verify the client was called with correct filters
134+ self .mock_client .get .assert_called_once_with (
135+ "/api/v1/timetable/" ,
136+ query = {
137+ "filename" : "test.xlsx" ,
138+ "start_date" : "2026-01-01T00:00:00Z"
139+ }
140+ )
141+
142+ # Verify results
143+ self .assertEqual (len (result ), 1 )
144+ self .assertEqual (result [0 ].filename , "test.xlsx" )
145+
146+ def test_list_propagates_client_errors (self ):
147+ """Test list() propagates client errors."""
148+ # Mock response with raise_for_status that raises exception
149+ mock_response = Mock ()
150+ mock_response .raise_for_status .side_effect = Exception ("Client error" )
151+
152+ self .mock_client .get .return_value = mock_response
153+
154+ # Call list() should raise exception
155+ with self .assertRaises (Exception ) as context :
156+ self .timetables .list ()
157+
158+ self .assertEqual (str (context .exception ), "Client error" )
159+
160+
161+ if __name__ == "__main__" :
162+ unittest .main ()
0 commit comments