dart-lang / mockito

Mockito-inspired mock library for Dart
https://pub.dev/packages/mockito
Apache License 2.0
634 stars 162 forks source link

`thenAnswer` Invocation with callback positional parameter does not handle non-primitives when compiled with dart2js #198

Open smaifullerton-wk opened 5 years ago

smaifullerton-wk commented 5 years ago

Here is a simplified test case of a bug I'm seeing with the thenAnswer Invocation when this code is compiled with dart2js. With DDC, it works as expected:

import 'package:test/test.dart';
import 'package:mockito/mockito.dart';

void main() {
  group('MockBassetHound', () {
    MockBassetHound bassetHound;

    setUp(() {
      bassetHound = MockBassetHound();
    });

    test('demonstrates bug', () {
      when(bassetHound.takesACallback(any)).thenAnswer((Invocation inv) {
        var callback = inv.positionalArguments[0];
        callback(new BassetPayload('Gerald'));
      });

      var callbackParam = ((BassetPayload payload) {
        print(payload == null); // false
        print(payload.runtimeType); // BassetPayload

        // NoSuchMethodError: method not found: 'get$name' (thing.get$name is not a function)
        expect(payload.name, 'Gerald');
      });

      bassetHound.takesACallback(callbackParam);
    });
  });
}

class MockBassetHound extends Mock implements BassetHound {}

class BassetHound {
  void takesACallback(Function cb) {}
}

class BassetPayload {
  final String name;

  BassetPayload(this.name);
}

There are no issues if the callback payload is a primitive.

It appears that Invocation with a callback argument works correctly on its own with this simplified case:

void main() async {
  var cb = (Rotsky rotsky) => print(rotsky.name);
  var inv = new Invocation.method(new Symbol('printName'), [cb]);

  inv.positionalArguments[0](new Rotsky('Lucy')); // 'Lucy'
}

class Rotsky {
  final String name;

  Rotsky(this.name);
}

Thank you for taking a look.

srawlins commented 5 years ago

First of all, I have to thank you, so so much, on a stellar bug report. 👏 👏 👏 Thank you for the craftsmanship in the minimal reproduction, for the thoughtful embedded debug statements, and for the note about dart2js vs DDC. I can't guess at how long you've been trying to figure this problem out, in order to ultimately come up with this detailed report.

I've been able to reproduce this bug exactly (DDC is happy, dart2js is not). I'll look into it; seems like it may be a dart2js bug...

srawlins commented 5 years ago

I believe this is a dart2js bug. I've filed https://github.com/dart-lang/sdk/issues/37322.

travissanderson-wf commented 5 years ago

@srawlins any update on when this might be looked at? the dart2js issue has no movement on it as of yet

srawlins commented 5 years ago

No fix on dart2js yet, but we just found a cause and workaround at https://github.com/dart-lang/sdk/issues/37322#issuecomment-540898984.