6
6
7
7
import os
8
8
from pathlib import Path
9
+ from typing import cast
9
10
from unittest .mock import Mock
10
11
11
12
import can
13
+ from can .io .generic import FileIOMessageWriter
14
+ from can .typechecking import StringPathLike
12
15
13
16
from .data .example_data import generate_message
14
17
15
18
16
19
class TestBaseRotatingLogger :
17
20
@staticmethod
18
- def _get_instance (path , * args , ** kwargs ) -> can .io .BaseRotatingLogger :
21
+ def _get_instance (file : StringPathLike ) -> can .io .BaseRotatingLogger :
19
22
class SubClass (can .io .BaseRotatingLogger ):
20
23
"""Subclass that implements abstract methods for testing."""
21
24
22
25
_supported_formats = {".asc" , ".blf" , ".csv" , ".log" , ".txt" }
23
26
24
- def __init__ (self , * args , ** kwargs ) -> None :
25
- super ().__init__ (* args , ** kwargs )
26
- self ._writer = can .Printer (file = path / "__unused.txt" )
27
+ def __init__ (self , file : StringPathLike , ** kwargs ) -> None :
28
+ super ().__init__ (** kwargs )
29
+ suffix = Path (file ).suffix .lower ()
30
+ if suffix not in self ._supported_formats :
31
+ raise ValueError (f"Unsupported file format: { suffix } " )
32
+ self ._writer = can .Printer (file = file )
33
+
34
+ @property
35
+ def writer (self ) -> FileIOMessageWriter :
36
+ return cast (FileIOMessageWriter , self ._writer )
27
37
28
38
def should_rollover (self , msg : can .Message ) -> bool :
29
39
return False
30
40
31
41
def do_rollover (self ):
32
42
...
33
43
34
- return SubClass (* args , ** kwargs )
44
+ return SubClass (file = file )
35
45
36
46
def test_import (self ):
37
47
assert hasattr (can .io , "BaseRotatingLogger" )
@@ -50,90 +60,82 @@ def test_attributes(self):
50
60
assert hasattr (can .io .BaseRotatingLogger , "do_rollover" )
51
61
52
62
def test_get_new_writer (self , tmp_path ):
53
- logger_instance = self ._get_instance (tmp_path )
54
-
55
- writer = logger_instance ._get_new_writer (tmp_path / "file.ASC" )
56
- assert isinstance (writer , can .ASCWriter )
57
- writer .stop ()
63
+ with self ._get_instance (tmp_path / "__unused.txt" ) as logger_instance :
64
+ writer = logger_instance ._get_new_writer (tmp_path / "file.ASC" )
65
+ assert isinstance (writer , can .ASCWriter )
66
+ writer .stop ()
58
67
59
- writer = logger_instance ._get_new_writer (tmp_path / "file.BLF" )
60
- assert isinstance (writer , can .BLFWriter )
61
- writer .stop ()
68
+ writer = logger_instance ._get_new_writer (tmp_path / "file.BLF" )
69
+ assert isinstance (writer , can .BLFWriter )
70
+ writer .stop ()
62
71
63
- writer = logger_instance ._get_new_writer (tmp_path / "file.CSV" )
64
- assert isinstance (writer , can .CSVWriter )
65
- writer .stop ()
72
+ writer = logger_instance ._get_new_writer (tmp_path / "file.CSV" )
73
+ assert isinstance (writer , can .CSVWriter )
74
+ writer .stop ()
66
75
67
- writer = logger_instance ._get_new_writer (tmp_path / "file.LOG" )
68
- assert isinstance (writer , can .CanutilsLogWriter )
69
- writer .stop ()
76
+ writer = logger_instance ._get_new_writer (tmp_path / "file.LOG" )
77
+ assert isinstance (writer , can .CanutilsLogWriter )
78
+ writer .stop ()
70
79
71
- writer = logger_instance ._get_new_writer (tmp_path / "file.TXT" )
72
- assert isinstance (writer , can .Printer )
73
- writer .stop ()
80
+ writer = logger_instance ._get_new_writer (tmp_path / "file.TXT" )
81
+ assert isinstance (writer , can .Printer )
82
+ writer .stop ()
74
83
75
84
def test_rotation_filename (self , tmp_path ):
76
- logger_instance = self ._get_instance (tmp_path )
85
+ with self ._get_instance (tmp_path / "__unused.txt" ) as logger_instance :
86
+ default_name = "default"
87
+ assert logger_instance .rotation_filename (default_name ) == "default"
77
88
78
- default_name = "default"
79
- assert logger_instance .rotation_filename (default_name ) == "default"
80
-
81
- logger_instance .namer = lambda x : x + "_by_namer"
82
- assert logger_instance .rotation_filename (default_name ) == "default_by_namer"
89
+ logger_instance .namer = lambda x : x + "_by_namer"
90
+ assert logger_instance .rotation_filename (default_name ) == "default_by_namer"
83
91
84
92
def test_rotate_without_rotator (self , tmp_path ):
85
- logger_instance = self ._get_instance (tmp_path )
86
-
87
- source = str (tmp_path / "source.txt" )
88
- dest = str (tmp_path / "dest.txt" )
93
+ with self ._get_instance (tmp_path / "__unused.txt" ) as logger_instance :
94
+ source = str (tmp_path / "source.txt" )
95
+ dest = str (tmp_path / "dest.txt" )
89
96
90
- assert os .path .exists (source ) is False
91
- assert os .path .exists (dest ) is False
97
+ assert os .path .exists (source ) is False
98
+ assert os .path .exists (dest ) is False
92
99
93
- logger_instance ._writer = logger_instance ._get_new_writer (source )
94
- logger_instance .stop ()
100
+ logger_instance ._writer = logger_instance ._get_new_writer (source )
101
+ logger_instance .stop ()
95
102
96
- assert os .path .exists (source ) is True
97
- assert os .path .exists (dest ) is False
103
+ assert os .path .exists (source ) is True
104
+ assert os .path .exists (dest ) is False
98
105
99
- logger_instance .rotate (source , dest )
106
+ logger_instance .rotate (source , dest )
100
107
101
- assert os .path .exists (source ) is False
102
- assert os .path .exists (dest ) is True
108
+ assert os .path .exists (source ) is False
109
+ assert os .path .exists (dest ) is True
103
110
104
111
def test_rotate_with_rotator (self , tmp_path ):
105
- logger_instance = self ._get_instance (tmp_path )
106
-
107
- rotator_func = Mock ()
108
- logger_instance .rotator = rotator_func
112
+ with self ._get_instance (tmp_path / "__unused.txt" ) as logger_instance :
113
+ rotator_func = Mock ()
114
+ logger_instance .rotator = rotator_func
109
115
110
- source = str (tmp_path / "source.txt" )
111
- dest = str (tmp_path / "dest.txt" )
116
+ source = str (tmp_path / "source.txt" )
117
+ dest = str (tmp_path / "dest.txt" )
112
118
113
- assert os .path .exists (source ) is False
114
- assert os .path .exists (dest ) is False
119
+ assert os .path .exists (source ) is False
120
+ assert os .path .exists (dest ) is False
115
121
116
- logger_instance ._writer = logger_instance ._get_new_writer (source )
117
- logger_instance .stop ()
122
+ logger_instance ._writer = logger_instance ._get_new_writer (source )
123
+ logger_instance .stop ()
118
124
119
- assert os .path .exists (source ) is True
120
- assert os .path .exists (dest ) is False
125
+ assert os .path .exists (source ) is True
126
+ assert os .path .exists (dest ) is False
121
127
122
- logger_instance .rotate (source , dest )
123
- rotator_func .assert_called_with (source , dest )
128
+ logger_instance .rotate (source , dest )
129
+ rotator_func .assert_called_with (source , dest )
124
130
125
- # assert that no rotation was performed since rotator_func
126
- # does not do anything
127
- assert os .path .exists (source ) is True
128
- assert os .path .exists (dest ) is False
131
+ # assert that no rotation was performed since rotator_func
132
+ # does not do anything
133
+ assert os .path .exists (source ) is True
134
+ assert os .path .exists (dest ) is False
129
135
130
136
def test_stop (self , tmp_path ):
131
137
"""Test if stop() method of writer is called."""
132
- with self ._get_instance (tmp_path ) as logger_instance :
133
- logger_instance ._writer = logger_instance ._get_new_writer (
134
- tmp_path / "file.ASC"
135
- )
136
-
138
+ with self ._get_instance (tmp_path / "file.ASC" ) as logger_instance :
137
139
# replace stop method of writer with Mock
138
140
original_stop = logger_instance .writer .stop
139
141
mock_stop = Mock ()
@@ -146,44 +148,38 @@ def test_stop(self, tmp_path):
146
148
original_stop ()
147
149
148
150
def test_on_message_received (self , tmp_path ):
149
- logger_instance = self ._get_instance (tmp_path )
151
+ with self ._get_instance (tmp_path / "file.ASC" ) as logger_instance :
152
+ # Test without rollover
153
+ should_rollover = Mock (return_value = False )
154
+ do_rollover = Mock ()
155
+ writers_on_message_received = Mock ()
150
156
151
- logger_instance ._writer = logger_instance ._get_new_writer (tmp_path / "file.ASC" )
157
+ logger_instance .should_rollover = should_rollover
158
+ logger_instance .do_rollover = do_rollover
159
+ logger_instance .writer .on_message_received = writers_on_message_received
152
160
153
- # Test without rollover
154
- should_rollover = Mock (return_value = False )
155
- do_rollover = Mock ()
156
- writers_on_message_received = Mock ()
157
-
158
- logger_instance .should_rollover = should_rollover
159
- logger_instance .do_rollover = do_rollover
160
- logger_instance .writer .on_message_received = writers_on_message_received
161
-
162
- msg = generate_message (0x123 )
163
- logger_instance .on_message_received (msg )
164
-
165
- should_rollover .assert_called_with (msg )
166
- do_rollover .assert_not_called ()
167
- writers_on_message_received .assert_called_with (msg )
161
+ msg = generate_message (0x123 )
162
+ logger_instance .on_message_received (msg )
168
163
169
- # Test with rollover
170
- should_rollover = Mock (return_value = True )
171
- do_rollover = Mock ()
172
- writers_on_message_received = Mock ()
164
+ should_rollover .assert_called_with (msg )
165
+ do_rollover .assert_not_called ()
166
+ writers_on_message_received .assert_called_with (msg )
173
167
174
- logger_instance .should_rollover = should_rollover
175
- logger_instance .do_rollover = do_rollover
176
- logger_instance .writer .on_message_received = writers_on_message_received
168
+ # Test with rollover
169
+ should_rollover = Mock (return_value = True )
170
+ do_rollover = Mock ()
171
+ writers_on_message_received = Mock ()
177
172
178
- msg = generate_message (0x123 )
179
- logger_instance .on_message_received (msg )
173
+ logger_instance .should_rollover = should_rollover
174
+ logger_instance .do_rollover = do_rollover
175
+ logger_instance .writer .on_message_received = writers_on_message_received
180
176
181
- should_rollover .assert_called_with (msg )
182
- do_rollover .assert_called ()
183
- writers_on_message_received .assert_called_with (msg )
177
+ msg = generate_message (0x123 )
178
+ logger_instance .on_message_received (msg )
184
179
185
- # stop writer to enable cleanup of temp_dir
186
- logger_instance .stop ()
180
+ should_rollover .assert_called_with (msg )
181
+ do_rollover .assert_called ()
182
+ writers_on_message_received .assert_called_with (msg )
187
183
188
184
189
185
class TestSizedRotatingLogger :
@@ -202,54 +198,48 @@ def test_create_instance(self, tmp_path):
202
198
base_filename = "mylogfile.ASC"
203
199
max_bytes = 512
204
200
205
- logger_instance = can .SizedRotatingLogger (
201
+ with can .SizedRotatingLogger (
206
202
base_filename = tmp_path / base_filename , max_bytes = max_bytes
207
- )
208
- assert Path (logger_instance .base_filename ).name == base_filename
209
- assert logger_instance .max_bytes == max_bytes
210
- assert logger_instance .rollover_count == 0
211
- assert isinstance (logger_instance .writer , can .ASCWriter )
212
-
213
- logger_instance .stop ()
203
+ ) as logger_instance :
204
+ assert Path (logger_instance .base_filename ).name == base_filename
205
+ assert logger_instance .max_bytes == max_bytes
206
+ assert logger_instance .rollover_count == 0
207
+ assert isinstance (logger_instance .writer , can .ASCWriter )
214
208
215
209
def test_should_rollover (self , tmp_path ):
216
210
base_filename = "mylogfile.ASC"
217
211
max_bytes = 512
218
212
219
- logger_instance = can .SizedRotatingLogger (
213
+ with can .SizedRotatingLogger (
220
214
base_filename = tmp_path / base_filename , max_bytes = max_bytes
221
- )
222
- msg = generate_message (0x123 )
223
- do_rollover = Mock ()
224
- logger_instance .do_rollover = do_rollover
225
-
226
- logger_instance .writer .file .tell = Mock (return_value = 511 )
227
- assert logger_instance .should_rollover (msg ) is False
228
- logger_instance .on_message_received (msg )
229
- do_rollover .assert_not_called ()
215
+ ) as logger_instance :
216
+ msg = generate_message (0x123 )
217
+ do_rollover = Mock ()
218
+ logger_instance .do_rollover = do_rollover
230
219
231
- logger_instance .writer .file .tell = Mock (return_value = 512 )
232
- assert logger_instance .should_rollover (msg ) is True
233
- logger_instance .on_message_received (msg )
234
- do_rollover .assert_called ()
220
+ logger_instance .writer .file .tell = Mock (return_value = 511 )
221
+ assert logger_instance .should_rollover (msg ) is False
222
+ logger_instance .on_message_received (msg )
223
+ do_rollover .assert_not_called ()
235
224
236
- logger_instance .stop ()
225
+ logger_instance .writer .file .tell = Mock (return_value = 512 )
226
+ assert logger_instance .should_rollover (msg ) is True
227
+ logger_instance .on_message_received (msg )
228
+ do_rollover .assert_called ()
237
229
238
230
def test_logfile_size (self , tmp_path ):
239
231
base_filename = "mylogfile.ASC"
240
232
max_bytes = 1024
241
233
msg = generate_message (0x123 )
242
234
243
- logger_instance = can .SizedRotatingLogger (
235
+ with can .SizedRotatingLogger (
244
236
base_filename = tmp_path / base_filename , max_bytes = max_bytes
245
- )
246
- for _ in range (128 ):
247
- logger_instance .on_message_received (msg )
248
-
249
- for file_path in os .listdir (tmp_path ):
250
- assert os .path .getsize (tmp_path / file_path ) <= 1100
237
+ ) as logger_instance :
238
+ for _ in range (128 ):
239
+ logger_instance .on_message_received (msg )
251
240
252
- logger_instance .stop ()
241
+ for file_path in os .listdir (tmp_path ):
242
+ assert os .path .getsize (tmp_path / file_path ) <= 1100
253
243
254
244
def test_logfile_size_context_manager (self , tmp_path ):
255
245
base_filename = "mylogfile.ASC"
0 commit comments