diff --git a/lib/flame/component_controller.dart b/lib/flame/component_controller.dart index a4c9c572..94fa7c5c 100644 --- a/lib/flame/component_controller.dart +++ b/lib/flame/component_controller.dart @@ -14,19 +14,18 @@ abstract class ComponentController extends Component { /// The [Component] controlled by this [ComponentController]. final T component; - /// Ads the [ComponentController] to its [component]. - Future attach() async { - // TODO(alestiago): check if component already attached. - await component.add(this); - } - @override - Future onLoad() async { - await super.onLoad(); + Future addToParent(Component parent) async { assert( - parent! == component, + parent == component, 'ComponentController should be child of $component. ' 'Use attach() instead.', ); + await super.addToParent(parent); + } + + /// Ads the [ComponentController] to its [component]. + Future attach() async { + if (parent == null) await component.add(this); } } diff --git a/test/flame/component_controller_test.dart b/test/flame/component_controller_test.dart new file mode 100644 index 00000000..4124cedf --- /dev/null +++ b/test/flame/component_controller_test.dart @@ -0,0 +1,63 @@ +// ignore_for_file: cascade_invocations + +import 'package:flame/game.dart'; +import 'package:flame/src/components/component.dart'; +import 'package:flame_test/flame_test.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:pinball/flame/flame.dart'; + +class TestComponentController extends ComponentController { + TestComponentController(Component component) : super(component); +} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + final flameTester = FlameTester(FlameGame.new); + + group('ComponentController', () { + flameTester.test( + 'throws AssertionError when not attached to controlled component', + (game) async { + final component = Component(); + final controller = TestComponentController(component); + + final anotherComponet = Component(); + await expectLater( + () async => await anotherComponet.add(controller), + throwsAssertionError, + ); + }, + ); + + group('attach', () { + flameTester.test( + 'adds component controller to controlled component', + (game) async { + final component = Component(); + final controller = TestComponentController(component); + + await controller.attach(); + await game.add(component); + await game.ready(); + + expect(component.contains(controller), isTrue); + }, + ); + + flameTester.test( + "doesn't fail when already has a parent", + (game) async { + final component = Component(); + final controller = TestComponentController(component); + + await controller.attach(); + + await expectLater( + () async => controller.attach(), + returnsNormally, + ); + }, + ); + }); + }); +}