1111
1212TODO: correctly set preserves_channel and adds_default_channel
1313"""
14+ import locale
1415import logging
1516import os
1617import tempfile
1718import unittest
1819from abc import ABCMeta , abstractmethod
20+ from contextlib import contextmanager
1921from datetime import datetime
2022from itertools import zip_longest
23+ from pathlib import Path
24+ from unittest .mock import patch
2125
2226from parameterized import parameterized
2327
2428import can
2529from can .io import blf
26-
2730from .data .example_data import (
2831 TEST_COMMENTS ,
2932 TEST_MESSAGES_BASE ,
4245 asammdf = None
4346
4447
48+ @contextmanager
49+ def override_locale (category : int , locale_str : str ) -> None :
50+ prev_locale = locale .getlocale (category )
51+ locale .setlocale (category , locale_str )
52+ yield
53+ locale .setlocale (category , prev_locale )
54+
55+
4556class ReaderWriterExtensionTest (unittest .TestCase ):
4657 def _get_suffix_case_variants (self , suffix ):
4758 return [
@@ -403,12 +414,16 @@ def _setup_instance(self):
403414 adds_default_channel = 0 ,
404415 )
405416
417+ def _get_logfile_location (self , filename : str ) -> Path :
418+ my_dir = Path (__file__ ).parent
419+ return my_dir / "data" / filename
420+
406421 def _read_log_file (self , filename , ** kwargs ):
407- logfile = os . path . join ( os . path . dirname ( __file__ ), "data" , filename )
422+ logfile = self . _get_logfile_location ( filename )
408423 with can .ASCReader (logfile , ** kwargs ) as reader :
409424 return list (reader )
410425
411- def test_absolute_time (self ):
426+ def test_read_absolute_time (self ):
412427 time_from_file = "Sat Sep 30 10:06:13.191 PM 2017"
413428 start_time = datetime .strptime (
414429 time_from_file , self .FORMAT_START_OF_FILE_DATE
@@ -436,7 +451,7 @@ def test_absolute_time(self):
436451 actual = self ._read_log_file ("test_CanMessage.asc" , relative_timestamp = False )
437452 self .assertMessagesEqual (actual , expected_messages )
438453
439- def test_can_message (self ):
454+ def test_read_can_message (self ):
440455 expected_messages = [
441456 can .Message (
442457 timestamp = 2.5010 ,
@@ -459,7 +474,7 @@ def test_can_message(self):
459474 actual = self ._read_log_file ("test_CanMessage.asc" )
460475 self .assertMessagesEqual (actual , expected_messages )
461476
462- def test_can_remote_message (self ):
477+ def test_read_can_remote_message (self ):
463478 expected_messages = [
464479 can .Message (
465480 timestamp = 2.510001 ,
@@ -488,7 +503,7 @@ def test_can_remote_message(self):
488503 actual = self ._read_log_file ("test_CanRemoteMessage.asc" )
489504 self .assertMessagesEqual (actual , expected_messages )
490505
491- def test_can_fd_remote_message (self ):
506+ def test_read_can_fd_remote_message (self ):
492507 expected_messages = [
493508 can .Message (
494509 timestamp = 30.300981 ,
@@ -504,7 +519,7 @@ def test_can_fd_remote_message(self):
504519 actual = self ._read_log_file ("test_CanFdRemoteMessage.asc" )
505520 self .assertMessagesEqual (actual , expected_messages )
506521
507- def test_can_fd_message (self ):
522+ def test_read_can_fd_message (self ):
508523 expected_messages = [
509524 can .Message (
510525 timestamp = 30.005021 ,
@@ -541,7 +556,7 @@ def test_can_fd_message(self):
541556 actual = self ._read_log_file ("test_CanFdMessage.asc" )
542557 self .assertMessagesEqual (actual , expected_messages )
543558
544- def test_can_fd_message_64 (self ):
559+ def test_read_can_fd_message_64 (self ):
545560 expected_messages = [
546561 can .Message (
547562 timestamp = 30.506898 ,
@@ -566,7 +581,7 @@ def test_can_fd_message_64(self):
566581 actual = self ._read_log_file ("test_CanFdMessage64.asc" )
567582 self .assertMessagesEqual (actual , expected_messages )
568583
569- def test_can_and_canfd_error_frames (self ):
584+ def test_read_can_and_canfd_error_frames (self ):
570585 expected_messages = [
571586 can .Message (timestamp = 2.501000 , channel = 0 , is_error_frame = True ),
572587 can .Message (timestamp = 3.501000 , channel = 0 , is_error_frame = True ),
@@ -582,16 +597,16 @@ def test_can_and_canfd_error_frames(self):
582597 actual = self ._read_log_file ("test_CanErrorFrames.asc" )
583598 self .assertMessagesEqual (actual , expected_messages )
584599
585- def test_ignore_comments (self ):
600+ def test_read_ignore_comments (self ):
586601 _msg_list = self ._read_log_file ("logfile.asc" )
587602
588- def test_no_triggerblock (self ):
603+ def test_read_no_triggerblock (self ):
589604 _msg_list = self ._read_log_file ("issue_1256.asc" )
590605
591- def test_can_dlc_greater_than_8 (self ):
606+ def test_read_can_dlc_greater_than_8 (self ):
592607 _msg_list = self ._read_log_file ("issue_1299.asc" )
593608
594- def test_error_frame_channel (self ):
609+ def test_read_error_frame_channel (self ):
595610 # gh-issue 1578
596611 err_frame = can .Message (is_error_frame = True , channel = 4 )
597612
@@ -611,6 +626,31 @@ def test_error_frame_channel(self):
611626 finally :
612627 os .unlink (temp_file .name )
613628
629+ def test_write_millisecond_handling (self ):
630+ now = datetime (
631+ year = 2017 , month = 9 , day = 30 , hour = 15 , minute = 6 , second = 13 , microsecond = 191456
632+ )
633+
634+ # We temporarily set the locale to C to ensure test reproducibility
635+ with override_locale (category = locale .LC_TIME , locale_str = "C" ):
636+ # We mock datetime.now during ASCWriter __init__ for reproducibility
637+ # Unfortunately, now() is a readonly attribute, so we mock datetime
638+ with patch ("can.io.asc.datetime" ) as mock_datetime :
639+ mock_datetime .now .return_value = now
640+ writer = can .ASCWriter (self .test_file_name )
641+
642+ msg = can .Message (
643+ timestamp = now .timestamp (), arbitration_id = 0x123 , data = b"h"
644+ )
645+ writer .on_message_received (msg )
646+
647+ writer .stop ()
648+
649+ actual_file = Path (self .test_file_name )
650+ expected_file = self ._get_logfile_location ("single_frame_us_locale.asc" )
651+
652+ self .assertEqual (expected_file .read_text (), actual_file .read_text ())
653+
614654
615655class TestBlfFileFormat (ReaderWriterTest ):
616656 """Tests can.BLFWriter and can.BLFReader.
0 commit comments