"try/catch statement" check prevents Xtend-generated code from working #241

Closed
borisbrodski opened this Issue Nov 20, 2015 · 3 comments

Projects

None yet

3 participants

@borisbrodski

I'm the maintainer of the JMockit-Xtend project: https://github.com/borisbrodski/jmockit-xtend

With this project you can use JMockit directly from Xtend using much nicer syntax, like:

mock [
    service.processInt(with [ it > 0 ])
    result = 2
]

(Match the call to the service.processInt(int a) with any a > 0 and return 2)

During migration to the JMockit 1.20 (or 1.14) I hit the exception:

Invalid try/catch statement inside expectation block

This happens because of the fact, that Xtend generates mandatory try/catch block for each lambda expression. Lambdas are particularly useful to match arguments or to return custom results:

stub [
    service.generateEMail(any, any, any)
    result = [ String to, String subject, String body |
        '''
            To: «to»
            Subject: «subject»
            «body»
        '''.toString
    ]
]

Analyzing the code of JMockit I found no way to disable "try/catch statement" checking.

Could you please add a "disable try/catch statement" option to the next release?
Please keep in mind, that I don't have any control over "-D" java parameters.
A global static boolean field or local switch disabling the check just for the upcoming expectations-block will both do the trick.

Here are some additional snippets for you:

Xtend:

stub [
  expectationsAPI.paramsString(with [ (it ?: "").length > 3 ])
  result = "match1"
]

generates

final JMockitExtension.XtendNonStrictExpectations _function = new JMockitExtension.XtendNonStrictExpectations() {
  @Override
  public void apply(final ExpectationsDelegate it) {
    try {
      final Function1<String, Boolean> _function = new Function1<String, Boolean>() {
        public Boolean apply(final String it) {
          String _elvis = null;
          if (it != null) {
            _elvis = it;
          } else {
            _elvis = "";
          }
          int _length = _elvis.length();
          return Boolean.valueOf((_length > 3));
        }
      };
      String _with = it.<String>with(_function);
      WithMethodsWorkAsExpectedSpec.this.expectationsAPI.paramsString(_with);
      it.setResult("match1");
    } catch (Throwable _e) {
      throw Exceptions.sneakyThrow(_e);
    }
  }
};
JMockitExtension.stub(_function);
@rliesenfeld
Member

I think there's a better solution, which is to allow conditions/try..catchs inside methods, while still disallowing them inside constructors of the Expectations/Verifications subclass. I can make this change for the next release.

@rliesenfeld rliesenfeld self-assigned this Nov 20, 2015
@borisbrodski

Cool! Thank you!

PS
Are you aware of the fact, that I subclass XxxxxxExpectation and use JMockitExtension.XtendXxxxxxExpectations in the Xtend?

@rliesenfeld rliesenfeld added a commit that closed this issue Nov 22, 2015
@rliesenfeld rliesenfeld Relaxed the validation against conditions & try..catch statements ins…
…ide expectation blocks, by allowing them inside methods; closes #241.
7311b79
@sswilliam

Hi, I just started to use JMockIt in my unit testing and I feel this mock framework is really awesome. I also meet this questions when writing code for Verfications. I am just curious about why conditional checking is enabled in such blocks? Because from my point of view, it quite makes sense to support try/catch in such blocks. I suspect that I am not doing as the best practice if it is not supported.

Here is my code

//verify
        new Verifications(){
            {

                Object data;
                channel.writeAndFlush(data = withCapture());times = 1;
                assertTrue(data instanceof ByteBuf);

                try {
                    CodeProtobufPackPair pair = CodeProtobufPackUtils.unpack((ByteBuf)data);
                    assertEquals(MainServerProtocal.LOGIN, pair.code);
                    LoginResponse resp = LoginResponse.parseFrom(pair.data);
                    assertEquals(MainServerProtocal.COMMON_STATUS_PASS, resp.getStatus());
                } catch (Exception e) {
                    fail("test failed due to "+e.getMessage());
                    // TODO: handle exception
                }




            }
        };

I am doing some verifications to check whether returned protobuf data is correct or not. So I mocked the Channel object in Netty and captured the returned protobuf data. However the Protobuf will throws some exceptions and I have to use the try catch to avoid errors.

@rliesenfeld rliesenfeld locked and limited conversation to collaborators Dec 16, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.