@@ -41,10 +41,16 @@ class MockCodec implements Codec {
4141
4242 int numFramesAsked = 0 ;
4343
44+ bool disposed = false ;
45+
4446 Completer <FrameInfo > _nextFrameCompleter = Completer <FrameInfo >();
4547
4648 @override
4749 Future <FrameInfo > getNextFrame () {
50+ if (disposed) {
51+ throw StateError ('Codec is disposed' );
52+ }
53+
4854 numFramesAsked += 1 ;
4955 return _nextFrameCompleter.future;
5056 }
@@ -59,7 +65,13 @@ class MockCodec implements Codec {
5965 }
6066
6167 @override
62- void dispose () {}
68+ void dispose () {
69+ if (disposed) {
70+ throw StateError ('Codec is already disposed' );
71+ }
72+
73+ disposed = true ;
74+ }
6375}
6476
6577class FakeEventReportingImageStreamCompleter extends ImageStreamCompleter {
@@ -106,6 +118,7 @@ void main() {
106118 imageStream.addListener (ImageStreamListener (listener));
107119 await tester.idle ();
108120 expect (mockCodec.numFramesAsked, 1 );
121+ expect (mockCodec.disposed, false );
109122 });
110123
111124 testWidgets ('Decoding starts when a codec is ready after a listener is added' , (
@@ -130,6 +143,7 @@ void main() {
130143 completer.complete (mockCodec);
131144 await tester.idle ();
132145 expect (mockCodec.numFramesAsked, 1 );
146+ expect (mockCodec.disposed, false );
133147 });
134148
135149 testWidgets ('Decoding does not crash when disposed' , (WidgetTester tester) async {
@@ -156,7 +170,9 @@ void main() {
156170
157171 final FrameInfo frame = FakeFrameInfo (const Duration (milliseconds: 200 ), image20x10);
158172 mockCodec.completeNextFrame (frame);
173+ expect (mockCodec.disposed, false );
159174 imageStream.removeListener (streamListener);
175+ expect (mockCodec.disposed, true );
160176 await tester.idle ();
161177 });
162178
@@ -334,6 +350,7 @@ void main() {
334350 await tester.idle ();
335351
336352 expect (tester.takeException (), 'frame completion error' );
353+ expect (mockCodec.disposed, false );
337354 });
338355
339356 testWidgets ('ImageStream emits frame (static image)' , (WidgetTester tester) async {
@@ -362,7 +379,9 @@ void main() {
362379
363380 final FrameInfo frame = FakeFrameInfo (const Duration (milliseconds: 200 ), image20x10);
364381 mockCodec.completeNextFrame (frame);
382+ expect (mockCodec.disposed, false );
365383 await tester.idle ();
384+ expect (mockCodec.disposed, true );
366385
367386 expect (emittedImages.every ((ImageInfo info) => info.image.isCloneOf (frame.image)), true );
368387
@@ -420,7 +439,9 @@ void main() {
420439 // quit the test without pending timers.
421440 await tester.pump (const Duration (milliseconds: 400 ));
422441
442+ expect (mockCodec.disposed, false );
423443 imageStream.removeListener (listener);
444+ expect (mockCodec.disposed, true );
424445 imageCache.clear ();
425446 });
426447
@@ -469,7 +490,9 @@ void main() {
469490 // quit the test without pending timers.
470491 await tester.pump (const Duration (milliseconds: 200 ));
471492
493+ expect (mockCodec.disposed, false );
472494 imageStream.removeListener (listener);
495+ expect (mockCodec.disposed, true );
473496 imageCache.clear ();
474497 });
475498
@@ -505,7 +528,9 @@ void main() {
505528 await tester.pump (); // first animation frame shows on first app frame.
506529 mockCodec.completeNextFrame (frame2);
507530 await tester.idle (); // let nextFrameFuture complete
531+ expect (mockCodec.disposed, false );
508532 await tester.pump (const Duration (milliseconds: 200 )); // emit 2nd frame.
533+ expect (mockCodec.disposed, true );
509534 mockCodec.completeNextFrame (frame1);
510535 // allow another frame to complete (but we shouldn't be asking for it as
511536 // this animation should not repeat.
@@ -562,7 +587,9 @@ void main() {
562587 expect (mockCodec.numFramesAsked, 3 );
563588
564589 handle.dispose ();
590+ expect (mockCodec.disposed, false );
565591 imageStream.removeListener (listener);
592+ expect (mockCodec.disposed, true );
566593 imageCache.clear ();
567594 });
568595
@@ -619,7 +646,9 @@ void main() {
619646 expect (emittedImages2[0 ].image.isCloneOf (frame1.image), true );
620647 expect (emittedImages2[1 ].image.isCloneOf (frame2.image), true );
621648
649+ expect (mockCodec.disposed, false );
622650 imageStream.removeListener (listener2);
651+ expect (mockCodec.disposed, true );
623652 });
624653
625654 testWidgets ('timer is canceled when listeners are removed' , (WidgetTester tester) async {
@@ -653,7 +682,9 @@ void main() {
653682 await tester.idle (); // let nextFrameFuture complete
654683 await tester.pump ();
655684
685+ expect (mockCodec.disposed, false );
656686 imageStream.removeListener (ImageStreamListener (listener));
687+ expect (mockCodec.disposed, true );
657688 // The test framework will fail this if there are pending timers at this
658689 // point.
659690 });
@@ -699,7 +730,9 @@ void main() {
699730 expect (mockCodec.numFramesAsked, 3 );
700731 timeDilation = 1.0 ; // restore time dilation, or it will affect other tests
701732
733+ expect (mockCodec.disposed, false );
702734 imageStream.removeListener (listener);
735+ expect (mockCodec.disposed, true );
703736 });
704737
705738 testWidgets ('error handlers can intercept errors' , (WidgetTester tester) async {
@@ -734,6 +767,7 @@ void main() {
734767 // No exception is passed up.
735768 expect (tester.takeException (), isNull);
736769 expect (capturedException, 'frame completion error' );
770+ expect (mockCodec.disposed, false );
737771 });
738772
739773 testWidgets (
@@ -772,6 +806,7 @@ void main() {
772806 await tester.pump (); // first animation frame shows on first app frame.
773807
774808 await tester.pump (const Duration (milliseconds: 200 )); // emit 2nd frame.
809+ expect (mockCodec.disposed, false );
775810 },
776811 );
777812
@@ -918,7 +953,9 @@ void main() {
918953
919954 expect (onImageCount, 1 );
920955
956+ expect (mockCodec.disposed, false );
921957 handle.dispose ();
958+ expect (mockCodec.disposed, true );
922959 });
923960
924961 test ('MultiFrameImageStreamCompleter - one frame image should only be decoded once' , () async {
0 commit comments