diff --git a/packages/yx_scope/lib/src/core/scope_state.dart b/packages/yx_scope/lib/src/core/scope_state.dart index 0fe6adc..0c1f551 100644 --- a/packages/yx_scope/lib/src/core/scope_state.dart +++ b/packages/yx_scope/lib/src/core/scope_state.dart @@ -9,4 +9,8 @@ extension ScopeStateExt on ScopeState { bool get none => this == ScopeState.none; bool get available => this == ScopeState.available; + + bool get initializing => this == ScopeState.initializing; + + bool get disposing => this == ScopeState.disposing; } diff --git a/packages/yx_scope/lib/src/core_scope_holder.dart b/packages/yx_scope/lib/src/core_scope_holder.dart index a0e69f7..7a9bafa 100644 --- a/packages/yx_scope/lib/src/core_scope_holder.dart +++ b/packages/yx_scope/lib/src/core_scope_holder.dart @@ -15,7 +15,7 @@ abstract class CoreScopeHolder final _scopeStateHolder = ScopeStateHolder(ScopeState.none); Completer? _waitLifecycleCompleter; - ScopeState get _scopeState => _scopeStateHolder.scope; + ScopeState get state => _scopeStateHolder.scope; CoreScopeHolder({ List? scopeListeners, @@ -43,7 +43,7 @@ abstract class CoreScopeHolder if (scope is! Scope) { throw ScopeException('You must implement $Scope for your $Container'); } - switch (_scopeState) { + switch (state) { case ScopeState.initializing: throw ScopeException( 'You are trying to initialize $Container that is initializing right now. ' @@ -98,13 +98,13 @@ abstract class CoreScopeHolder _waitLifecycleCompleter = null; removeListener(); Logger.debug( - 'Wait for scope dispose has completed, state=$_scopeState', + 'Wait for scope dispose has completed, state=$state', ); - if (!_scopeState.none) { + if (!state.none) { throw ScopeError( 'Scope initialization waited for dispose of the previous scope state, ' 'it\'s expected to be ${ScopeState.none}, ' - 'but it appeared to be $_scopeState.' + 'but it appeared to be $state.' 'This is definitely an error in the library,' ' please contact an owner, if you see this message.', ); @@ -188,7 +188,7 @@ abstract class CoreScopeHolder 'both non-nullable args (drop during initialization)', ); } - switch (_scopeState) { + switch (state) { case ScopeState.disposing: assert( false, @@ -248,13 +248,13 @@ abstract class CoreScopeHolder _waitLifecycleCompleter = null; removeListener(); Logger.debug( - 'Wait for scope initialization has completed, state=$_scopeState', + 'Wait for scope initialization has completed, state=$state', ); - if (!_scopeState.available) { + if (!state.available) { throw ScopeError( 'Scope dispose waited for initialization of the previous scope state, ' 'it\'s expected to be ${ScopeState.available}, ' - 'but it appears to be $_scopeState. ' + 'but it appears to be $state. ' 'This is definitely an error in the library,' ' please contact an owner, if you see this message.', ); @@ -277,7 +277,7 @@ abstract class CoreScopeHolder final scope = this.scope as Container? ?? initializedScope; if (scope == null) { throw ScopeError( - '$Container must not be null if scope state is $_scopeState', + '$Container must not be null if scope state is $state', ); } diff --git a/packages/yx_scope/lib/yx_scope.dart b/packages/yx_scope/lib/yx_scope.dart index 849553a..19aab89 100644 --- a/packages/yx_scope/lib/yx_scope.dart +++ b/packages/yx_scope/lib/yx_scope.dart @@ -9,6 +9,7 @@ export 'src/base_scope_container.dart' TestableScopeStateHolder; export 'src/core/async_lifecycle.dart'; export 'src/core/scope_exception.dart'; +export 'src/core/scope_state.dart'; export 'src/monitoring/listeners.dart'; export 'src/monitoring/models/dep_id.dart'; export 'src/monitoring/models/scope_id.dart'; diff --git a/packages/yx_scope/test/scope_state_test.dart b/packages/yx_scope/test/scope_state_test.dart new file mode 100644 index 0000000..30fef24 --- /dev/null +++ b/packages/yx_scope/test/scope_state_test.dart @@ -0,0 +1,52 @@ +import 'dart:async'; + +import 'package:test/test.dart'; +import 'package:yx_scope/yx_scope.dart'; + +void main() { + test('scope state is valid according to updates', () async { + final scopeHolder = _TestScopeHolder(); + + final createCompleter = Completer(); + final dropCompleter = Completer(); + + expect(scopeHolder.state, ScopeState.none); + expect(scopeHolder.state.none, isTrue); + scopeHolder.create().then((_) => createCompleter.complete()); + + expect(scopeHolder.state, ScopeState.initializing); + expect(scopeHolder.state.initializing, isTrue); + await createCompleter.future; + + expect(scopeHolder.state, ScopeState.available); + expect(scopeHolder.state.available, isTrue); + + scopeHolder.drop().then((_) => dropCompleter.complete()); + + expect(scopeHolder.state, ScopeState.disposing); + expect(scopeHolder.state.disposing, isTrue); + + await dropCompleter.future; + + expect(scopeHolder.state, ScopeState.none); + expect(scopeHolder.state.none, isTrue); + }); +} + +class _TestScopeHolder extends ScopeHolder<_TestScopeContainer> { + @override + _TestScopeContainer createContainer() => _TestScopeContainer(); +} + +class _TestScopeContainer extends ScopeContainer { + @override + List> get initializeQueue => [ + {_asyncDep} + ]; + + late final _asyncDep = rawAsyncDep( + () => Future.delayed(Duration.zero), + init: (dep) async => await dep, + dispose: (dep) async {}, + ); +}