LCOV - code coverage report
Current view: top level - lib/services - event_bus.dart Coverage Total Hit
Test: lcov.info Lines: 77.8 % 194 151
Test Date: 2025-08-12 03:21:51 Functions: - 0 0

            Line data    Source code
       1              : import 'dart:async';
       2              : import 'dart:developer' as developer;
       3              : import 'package:flutter/foundation.dart';
       4              : import 'package:lanebow/utils/test_utils.dart';
       5              : import 'package:lanebow/utils/test_config.dart';
       6              : 
       7              : // 이벤트 클래스들 - 클래스 외부로 이동
       8              : class ClubChangedEvent {
       9              :   final String clubId;
      10              :   
      11            4 :   ClubChangedEvent(this.clubId);
      12              :   
      13            4 :   @override
      14            8 :   String toString() => 'ClubChangedEvent(clubId: $clubId)';
      15              :   
      16            0 :   @override
      17              :   bool operator ==(Object other) {
      18              :     if (identical(this, other)) return true;
      19            0 :     return other is ClubChangedEvent && other.clubId == clubId;
      20              :   }
      21              :   
      22            0 :   @override
      23            0 :   int get hashCode => clubId.hashCode;
      24              : }
      25              : 
      26              : class EventBus {
      27              :   // 테스트 환경에서 사용할 별도의 인스턴스 맵
      28           36 :   static final Map<String, EventBus> _testInstances = {};
      29              :   
      30              :   // 기본 싱글톤 인스턴스
      31           42 :   static final EventBus _instance = EventBus._internal();
      32              :   
      33              :   // 테스트 ID를 저장하는 변수 (테스트 격리용)
      34              :   static String? _currentTestId;
      35              :   
      36              :   // 테스트 환경 초기화 상태 추적
      37              :   static bool _isTestEnvironmentReady = false;
      38              :   
      39              :   // 테스트 환경 초기화 관련 로깅
      40           12 :   static void _logTestEnvironmentInit() {
      41              :     _isTestEnvironmentReady = true;
      42              :     if (kDebugMode) {
      43           24 :       debugPrint('EventBus: 테스트 환경 초기화 완료');
      44              :     }
      45              :   }
      46              :   
      47              :   // 활성 구독 수 추적 (디버깅 및 메모리 누수 감지용)
      48              :   static int _activeSubscriptionCount = 0;
      49              :   
      50              :   /// 현재 활성화된 테스트 인스턴스 수 반환
      51            3 :   static int get testInstanceCount => _testInstances.length;
      52              :   
      53              :   // 테스트 재시도 횟수 추적 및 관리
      54              :   static int _testRetryCount = 0;
      55              :   
      56              :   // 테스트 재시도 횟수 가져오기
      57            0 :   static int get testRetryCount => _testRetryCount;
      58              :   
      59              :   // 테스트 재시도 횟수 증가
      60            0 :   static void incrementRetryCount() {
      61            0 :     _testRetryCount++;
      62            0 :     if (kDebugMode || TestConfig.instance.isVerboseLogging) {
      63            0 :       debugPrint('EventBus: 테스트 재시도 횟수 증가 - $_testRetryCount');
      64              :     }
      65              :   }
      66              :   
      67              :   // 활성 구독 수 접근 게터
      68            2 :   static int get activeSubscriptionCount => _activeSubscriptionCount;
      69              :   
      70              :   // 현재 테스트 ID 설정 메서드
      71           12 :   static void setCurrentTestId(String testId) {
      72              :     // 테스트 설정 로드 확인 및 로깅
      73           12 :     final config = TestConfig.instance;
      74           12 :     if (config.isVerboseLogging) {
      75            0 :       debugPrint('EventBus: 테스트 설정 로드 - asyncTimeout=${config.asyncTimeout}ms, testDelay=${config.testDelay}ms');
      76              :     }
      77              :     // 이전 테스트 ID가 있으면 해당 인스턴스 정리
      78            1 :     if (_currentTestId != null && _currentTestId != testId) {
      79            2 :       if (_testInstances.containsKey(_currentTestId!)) {
      80              :         try {
      81            3 :           _testInstances[_currentTestId!]!.dispose();
      82              :         } catch (e) {
      83              :           if (kDebugMode) {
      84            0 :             debugPrint('EventBus: 이전 인스턴스 dispose 중 오류 - $e');
      85              :           }
      86              :         } finally {
      87            2 :           _testInstances.remove(_currentTestId!);
      88              :         }
      89              :       }
      90              :     }
      91              :     
      92              :     // 새 테스트 ID 설정
      93              :     _currentTestId = testId;
      94              :     
      95              :     // 새 테스트 ID에 대한 인스턴스가 없으면 생성
      96           24 :     if (!_testInstances.containsKey(testId)) {
      97           36 :       _testInstances[testId] = EventBus._internal();
      98              :     } else {
      99              :       // 이미 존재하는 인스턴스라도 초기화 수행
     100            3 :       _testInstances[testId]!.reset();
     101              :     }
     102              :     
     103              :     // 테스트 환경 초기화 로깅
     104           12 :     _logTestEnvironmentInit();
     105              :     
     106              :     // 활성 구독 수 초기화
     107              :     _activeSubscriptionCount = 0;
     108              :     
     109              :     // 테스트 재시도 횟수 초기화
     110              :     _testRetryCount = 0;
     111              :     
     112              :     if (kDebugMode) {
     113           36 :       debugPrint('EventBus: 테스트 ID 설정됨 - $testId');
     114           36 :       developer.log('EventBus 메모리 상태: $_testInstances', name: 'EventBus');
     115              :     }
     116              :   }
     117              :   
     118              :   // 현재 테스트 ID 초기화 메서드
     119           11 :   static Future<void> tearDownTestEnvironment() async {
     120            0 :     if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     121           22 :       debugPrint('EventBus: 테스트 환경 초기화 해제 시작');
     122              :     }
     123              :     
     124              :     // 테스트 환경 해제 전 비동기 리소스 상태 로깅
     125           11 :     await _logAsyncResourceState('테스트 환경 해제 전');
     126              :     
     127              :     // 테스트 종료 전 남아있는 타이머가 완료될 시간 제공
     128           11 :     await _ensureAllTimersComplete();
     129              :     
     130              :     // 현재 테스트 ID에 해당하는 인스턴스가 있는 경우 먼저 dispose 호출
     131           20 :     if (_currentTestId != null && _testInstances.containsKey(_currentTestId!)) {
     132              :       try {
     133            0 :         if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     134           30 :           debugPrint('EventBus: 현재 테스트 ID($_currentTestId) 인스턴스 dispose 시도');
     135              :         }
     136           30 :         await _testInstances[_currentTestId!]!.dispose();
     137              :       } catch (e) {
     138              :         if (kDebugMode) {
     139            0 :           debugPrint('EventBus: 현재 테스트 인스턴스 dispose 중 오류 - $e');
     140              :         }
     141              :       }
     142              :     }
     143              :     
     144              :     _currentTestId = null;
     145              :     // 테스트 환경 초기화 해제 로깅
     146              :     _isTestEnvironmentReady = false;
     147              :     if (kDebugMode) {
     148           22 :       debugPrint('EventBus: 테스트 환경 초기화 해제');
     149              :     }
     150              :     _activeSubscriptionCount = 0;
     151              :     
     152              :     // 테스트 환경 해제 후 비동기 리소스 상태 로깅
     153           11 :     await _logAsyncResourceState('테스트 환경 해제 후');
     154              :     
     155              :     // 메모리 누수 방지를 위해 GC 힌트 추가
     156           11 :     if (TestUtils.isInTest) {
     157            2 :       developer.log('EventBus 메모리 정리 요청', name: 'EventBus');
     158              :     }
     159              :     
     160              :     // 추가 마이크로태스크 실행으로 비동기 작업 완료 보장
     161           22 :     await Future.microtask(() {});
     162           22 :     await Future.microtask(() {});
     163              :   }
     164              :   
     165              :   // 테스트 ID 초기화 (후방 호환성을 위해 유지)
     166           10 :   static Future<void> clearCurrentTestId() async {
     167              :     // tearDownTestEnvironment로 대체되었지만 후방 호환성을 위해 유지
     168           10 :     await tearDownTestEnvironment();
     169              :   }
     170              :   
     171              :   // 모든 테스트 인스턴스를 정리하는 정적 메서드
     172            1 :   static Future<void> resetAllTestInstances() async {
     173            2 :     if (_testInstances.isEmpty) {
     174              :       return;
     175              :     }
     176              :     
     177            0 :     if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     178            5 :       debugPrint('EventBus: 모든 테스트 인스턴스 초기화 시작 (인스턴스 수: ${_testInstances.length})');
     179              :     }
     180              :     
     181              :     // 초기화 전 비동기 리소스 상태 로깅
     182            1 :     await _logAsyncResourceState('모든 테스트 인스턴스 초기화 전');
     183              :     
     184              :     // 기존 인스턴스 모두 정리
     185            3 :     for (var entry in _testInstances.entries) {
     186              :       try {
     187              :         if (kDebugMode) {
     188            4 :           debugPrint('EventBus: 인스턴스 정리 중 - ${entry.key}');
     189              :         }
     190            2 :         entry.value.dispose(); // 완전히 dispose 호출
     191              :         
     192              :         // 각 인스턴스 dispose 후 마이크로태스크 실행으로 비동기 작업 완료 보장
     193            2 :         await Future.microtask(() {});
     194              :       } catch (e) {
     195              :         // dispose 중 오류 무시
     196              :         if (kDebugMode) {
     197            0 :           debugPrint('EventBus: 인스턴스 정리 중 오류 - $e');
     198              :         }
     199              :       }
     200              :     }
     201              :     
     202              :     // 인스턴스 정리 후 중간 상태 로깅
     203            1 :     await _logAsyncResourceState('테스트 인스턴스 dispose 후, 초기화 전');
     204              :     
     205              :     // 모든 테스트 인스턴스 제거
     206            2 :     _testInstances.clear();
     207              :     
     208              :     // 기본 인스턴스도 초기화
     209              :     try {
     210            2 :       _instance.reset();
     211            2 :       await Future.microtask(() {}); // 기본 인스턴스 초기화 후 마이크로태스크 실행
     212              :     } catch (e) {
     213              :       // 기본 인스턴스 초기화 중 오류 무시
     214              :       if (kDebugMode) {
     215            0 :         debugPrint('EventBus: 기본 인스턴스 초기화 중 오류 - $e');
     216              :       }
     217              :     }
     218              :     
     219              :     // 현재 테스트 ID도 초기화
     220              :     _currentTestId = null;
     221              :     // 테스트 환경 초기화 해제 로깅
     222              :     if (_isTestEnvironmentReady) {
     223              :       _isTestEnvironmentReady = false;
     224              :       if (kDebugMode) {
     225            2 :         debugPrint('EventBus: 모든 테스트 환경 초기화 해제');
     226              :       }
     227              :     }
     228              :     _activeSubscriptionCount = 0;
     229              :     
     230              :     // 비동기 작업이 완료될 시간을 제공하되, 타이머 생성 없이 동기화
     231              :     // 타이머 생성 없이 마이크로태스크 큐 완료 보장
     232            2 :     await Future.microtask(() {});
     233            2 :     await Future.microtask(() {});
     234              :     
     235              :     // 테스트 종료 전 남아있는 타이머가 완료될 시간 제공
     236              :     // 테스트 환경에서 !timersPending assertion 실패 방지
     237            1 :     await _ensureAllTimersComplete();
     238              :     
     239              :     // 초기화 완료 후 비동기 리소스 상태 로깅
     240            1 :     await _logAsyncResourceState('모든 테스트 인스턴스 초기화 후');
     241              :     
     242            0 :     if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     243            2 :       debugPrint('EventBus: 모든 테스트 인스턴스 초기화됨');
     244            1 :       developer.log('EventBus 메모리 상태 초기화 완료', name: 'EventBus');
     245              :     }
     246              :   }
     247              :   
     248              :   // 비동기 리소스 상태 진단 및 로깅
     249           11 :   static Future<Map<String, dynamic>> _diagnoseAsyncResources() async {
     250           11 :     final diagnosticInfo = <String, dynamic>{
     251           22 :       'timestamp': DateTime.now().toIso8601String(),
     252              :       'activeSubscriptions': _activeSubscriptionCount,
     253           22 :       'testInstances': _testInstances.length,
     254              :       'currentTestId': _currentTestId,
     255              :       'isTestEnvironmentReady': _isTestEnvironmentReady,
     256              :       'testRetryCount': _testRetryCount,
     257              :     };
     258              :     
     259              :     // 인스턴스별 상태 수집
     260           11 :     final instanceStates = <String, Map<String, dynamic>>{};
     261           33 :     for (final entry in _testInstances.entries) {
     262           33 :       instanceStates[entry.key] = {
     263           22 :         'isDisposed': entry.value._isDisposed,
     264           33 :         'isStreamControllerClosed': entry.value._streamController.isClosed,
     265              :       };
     266              :     }
     267           11 :     diagnosticInfo['instanceStates'] = instanceStates;
     268              :     
     269              :     // 기본 인스턴스 상태
     270           22 :     diagnosticInfo['defaultInstance'] = {
     271           22 :       'isDisposed': _instance._isDisposed,
     272           33 :       'isStreamControllerClosed': _instance._streamController.isClosed,
     273              :     };
     274              :     
     275              :     return diagnosticInfo;
     276              :   }
     277              :   
     278              :   // 비동기 리소스 상태 로깅
     279           11 :   static Future<void> _logAsyncResourceState(String context) async {
     280            0 :     if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     281           11 :       final diagnosticInfo = await _diagnoseAsyncResources();
     282           33 :       debugPrint('===== EventBus 비동기 리소스 상태 ($context) =====');
     283           44 :       debugPrint('시간: ${diagnosticInfo['timestamp']}');
     284           44 :       debugPrint('활성 구독 수: ${diagnosticInfo['activeSubscriptions']}');
     285           44 :       debugPrint('테스트 인스턴스 수: ${diagnosticInfo['testInstances']}');
     286           44 :       debugPrint('현재 테스트 ID: ${diagnosticInfo['currentTestId']}');
     287           44 :       debugPrint('테스트 환경 준비 상태: ${diagnosticInfo['isTestEnvironmentReady']}');
     288           44 :       debugPrint('테스트 재시도 횟수: ${diagnosticInfo['testRetryCount']}');
     289              :       
     290              :       // 인스턴스별 상태 출력
     291           11 :       final instanceStates = diagnosticInfo['instanceStates'] as Map<String, Map<String, dynamic>>;
     292           11 :       if (instanceStates.isNotEmpty) {
     293           22 :         debugPrint('--- 테스트 인스턴스 상태 ---');
     294           22 :         instanceStates.forEach((key, value) {
     295           55 :           debugPrint('  $key: disposed=${value['isDisposed']}, streamClosed=${value['isStreamControllerClosed']}');
     296              :         });
     297              :       }
     298              :       
     299              :       // 기본 인스턴스 상태
     300           11 :       final defaultInstance = diagnosticInfo['defaultInstance'] as Map<String, dynamic>;
     301           22 :       debugPrint('--- 기본 인스턴스 상태 ---');
     302           55 :       debugPrint('  disposed=${defaultInstance['isDisposed']}, streamClosed=${defaultInstance['isStreamControllerClosed']}');
     303              :       
     304           22 :       debugPrint('===========================================');
     305              :     }
     306              :   }
     307              :   
     308           11 :   static Future<void> _ensureAllTimersComplete() async {
     309            0 :     if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     310           22 :       debugPrint('EventBus: 타이머 완료 대기 시작');
     311              :     }
     312              :     
     313              :     // 비동기 리소스 상태 로깅 (시작)
     314           11 :     await _logAsyncResourceState('타이머 완료 대기 시작');
     315              :     
     316              :     // 타이머를 새로 만들지 않기 위해 microtask만 사용
     317           22 :     await Future.microtask(() {});
     318           22 :     await Future.microtask(() {});
     319           22 :     await Future.microtask(() {});
     320              :     
     321              :     // 중간 상태 로깅
     322           11 :     await _logAsyncResourceState('타이머 완료 중간 상태');
     323              :     
     324              :     // 테스트 설정에서 정의된 타이머 완료 대기 시간을 적용
     325              :     // 추가 대기 시간이 설정되어 있어도 실제 Timer 생성은 하지 않음(테스트 타이머 경합 방지)
     326              :     // 필요한 경우 호출자에서 fakeAsync 등을 사용해 제어하도록 위임
     327              :     
     328              :     // 비동기 리소스 상태 로깅 (완료)
     329           11 :     await _logAsyncResourceState('타이머 완료 대기 완료');
     330              :     
     331            0 :     if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     332           22 :       debugPrint('EventBus: 타이머 완료 대기 완료');
     333              :     }
     334              :   }
     335              :   
     336           11 :   factory EventBus() {
     337              :     // 테스트 환경에서는 테스트 ID 자동 생성 및 설정
     338           11 :     if (TestUtils.isInTest) {
     339              :       // 테스트 ID가 설정되지 않았다면 자동으로 생성하지 말고, 명시적 설정을 강제한다
     340              :       if (_currentTestId == null) {
     341            0 :         throw StateError('EventBus: 테스트 환경에서 currentTestId가 설정되지 않았습니다. setUp에서 EventBus.setCurrentTestId(...)를 호출하세요.');
     342              :       }
     343              :       
     344              :       // 테스트 ID가 있지만 인스턴스가 없는 경우 생성
     345           16 :       if (!_testInstances.containsKey(_currentTestId!)) {
     346              :         if (kDebugMode) {
     347            0 :           debugPrint('EventBus: 테스트 ID ${_currentTestId}에 대한 새 인스턴스 생성');
     348              :         }
     349            0 :         _testInstances[_currentTestId!] = EventBus._internal();
     350            0 :         _testInstances[_currentTestId!]!.reset();
     351              :       }
     352              :       
     353           16 :       return _testInstances[_currentTestId]!;
     354              :     }
     355              :     
     356              :     // 테스트 환경이 아닌 경우 기본 싱글톤 인스턴스 반환
     357            3 :     return _instance;
     358              :   }
     359              :   
     360           15 :   EventBus._internal();
     361              :   
     362              :   // 이벤트 버스 내부 상태
     363              :   StreamController _streamController = StreamController.broadcast();
     364              :   bool _isDisposed = false;
     365              :   
     366           12 :   Stream get stream => _streamController.stream;
     367              :   
     368            4 :   void fire(dynamic event) {
     369           12 :     if (!_isDisposed && !_streamController.isClosed) {
     370            8 :       _streamController.add(event);
     371              :       // 디버그 모드 또는 상세 로깅 설정 시 이벤트 발생 로그 추가
     372            0 :       if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     373           12 :         debugPrint('EventBus: 이벤트 발생 - $event');
     374              :       }
     375            0 :     } else if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     376            0 :       debugPrint('EventBus: 이벤트 발생 실패 (이미 dispose됨) - $event');
     377              :     }
     378              :   }
     379              :   
     380              :   // 특정 타입의 이벤트를 구독하는 메서드
     381            4 :   Stream<T> on<T>() {
     382            4 :     if (_isDisposed) {
     383            0 :       if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     384            0 :         debugPrint('EventBus: dispose된 인스턴스에서 on<$T> 호출됨');
     385              :       }
     386              :       // 빈 스트림 반환
     387            0 :       return Stream<T>.empty();
     388              :     }
     389              :     
     390              :     // 타입 필터링 및 변환
     391           20 :     final filteredStream = stream.where((event) => event is T).cast<T>();
     392              :     
     393              :     // 구독 생성 시 카운터 증가 - 한 번만 증가
     394            4 :     _activeSubscriptionCount++;
     395              :     
     396            4 :     if (TestUtils.isInTest) {
     397            0 :       if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     398           12 :         debugPrint('EventBus: 새 구독 추가됨 <$T> (현재 구독 수: $_activeSubscriptionCount)');
     399              :       }
     400              :       
     401              :       // 구독 취소 시 카운터 감소를 위한 처리
     402              :       // StreamController를 사용하여 구독 취소 시 카운터 감소 보장
     403            4 :       final controller = StreamController<T>();
     404              :       
     405              :       // 원본 스트림에서 데이터 수신 및 전달
     406            4 :       final subscription = filteredStream.listen(
     407            8 :         (data) => controller.add(data),
     408            0 :         onError: (error) => controller.addError(error),
     409            2 :         onDone: () => controller.close(),
     410              :       );
     411              :       
     412              :       // 컨트롤러 닫힐 때 구독 취소 및 카운터 감소
     413            8 :       controller.onCancel = () {
     414            4 :         subscription.cancel();
     415            8 :         _activeSubscriptionCount = (_activeSubscriptionCount > 0) ? _activeSubscriptionCount - 1 : 0;
     416            0 :         if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     417           12 :           debugPrint('EventBus: 구독 취소됨 <$T> (남은 구독 수: $_activeSubscriptionCount)');
     418              :         }
     419              :       };
     420              :       
     421            4 :       return controller.stream;
     422              :     }
     423              :     
     424              :     return filteredStream;
     425              :   }
     426              : 
     427           15 :   Future<void> _logInstanceState() async {
     428            0 :     if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     429           30 :       debugPrint('EventBus 인스턴스 상태:');
     430           60 :       debugPrint('  isDisposed: $_isDisposed');
     431           75 :       debugPrint('  streamController.isClosed: ${_streamController.isClosed}');
     432           15 :       if (TestUtils.isInTest) {
     433           21 :         debugPrint('  현재 테스트 ID: $_currentTestId');
     434           21 :         debugPrint('  활성 구독 수: $_activeSubscriptionCount');
     435              :       }
     436              :     }
     437              :   }
     438              :   
     439           15 :   Future<void> dispose() async {
     440           15 :     if (!_isDisposed) {
     441              :       // dispose 전 상태 로깅
     442            0 :       if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     443           30 :         debugPrint('EventBus: dispose 시작');
     444           15 :         await _logInstanceState();
     445              :       }
     446              :       
     447           15 :       _isDisposed = true;
     448           30 :       if (!_streamController.isClosed) {
     449              :         try {
     450           30 :           await _streamController.close();
     451              :           
     452              :           // 마이크로태스크 실행으로 비동기 작업 완료 보장
     453           30 :           await Future.microtask(() {});
     454              :           
     455           15 :           if ((kDebugMode || TestConfig.instance.isVerboseLogging) && TestUtils.isInTest) {
     456           21 :             debugPrint('EventBus: 인스턴스 dispose 완료 (테스트 ID: $_currentTestId)');
     457              :             // dispose 후 상태 로깅
     458            7 :             await _logInstanceState();
     459              :           }
     460              :         } catch (e) {
     461            0 :           if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     462            0 :             debugPrint('EventBus: dispose 중 오류 - $e');
     463              :           }
     464              :         }
     465              :       }
     466            0 :     } else if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     467            0 :       debugPrint('EventBus: 이미 dispose된 인스턴스에 dispose 호출됨');
     468              :     }
     469              :   }
     470              : 
     471              :   /// 테스트 환경에서 EventBus를 초기화하는 메서드
     472              :   /// 기존 StreamController를 닫고 새로운 것으로 교체
     473            9 :   Future<void> reset() async {
     474            0 :     if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     475           18 :       debugPrint('EventBus: reset 시작');
     476            9 :       await _logInstanceState();
     477              :     }
     478              :     
     479            9 :     if (!_isDisposed) {
     480              :       try {
     481            8 :         await dispose();
     482              :       } catch (e) {
     483              :         if (kDebugMode) {
     484            0 :           debugPrint('EventBus: reset 중 dispose 호출 오류 - $e');
     485              :         }
     486              :       }
     487              :     }
     488              :     
     489              :     // 새로운 StreamController 생성
     490           18 :     _streamController = StreamController.broadcast();
     491            9 :     _isDisposed = false;
     492              :     
     493              :     // 활성 구독 수 초기화 (인스턴스 레벨)
     494            9 :     if (TestUtils.isInTest) {
     495              :       _activeSubscriptionCount = 0;
     496              :     }
     497              :     
     498              :     // 마이크로태스크 실행으로 비동기 작업 완료 보장
     499           18 :     await Future.microtask(() {});
     500              :     
     501            0 :     if (kDebugMode || TestConfig.instance.isVerboseLogging) {
     502           27 :       debugPrint('EventBus: 인스턴스 reset 완료 (테스트 ID: $_currentTestId)');
     503            9 :       await _logInstanceState();
     504              :     }
     505              :   }
     506              : }
        

Generated by: LCOV version 2.3.1-1