misprintt / mockatoo

A cross platform mocking framework for Haxe. Supports JavaScript, Flash, C++, PHP and Neko.
MIT License
49 stars 31 forks source link

Matching against parameters with default values #21

Closed lptr closed 10 years ago

lptr commented 11 years ago

This works running the tests with Flash:

import mockatoo.Mockatoo.*;
using mockatoo.Mockatoo;

class Test extends org.hamcrest.MatchersBase {

    @Test
    @TestDebug
    public function test()
    {
        var m = mock(Something);
        assertThat(m.returnSomething("lajos"), is(null));
        m.returnSomething(cast anyString, 0).returns("tibor");
        assertThat(m.returnSomething("lajos"), is("tibor"));
    }

}

interface Something {
    public function returnSomething(something:String, other:Int = 0):String;
}

The same code breaks in JS:

Failure: test (0s)
massive.munit.AssertionException: 
Expected: is 'tibor'
     but: was null at prezi.graphics.text.Test#test (15)

However, using null instead of 0 makes it work in JS:

m.returnSomething(cast anyString, null).returns("tibor");

…but breaks it in Flash:

Failure: test (0.011s)
massive.munit.AssertionException: 
Expected: is 'tibor'
     but: was null at prezi.graphics.text.Test#test (15)

A side note: changing the default value given (0 in the above example) does not make any difference. If I change it to 7 like this:

interface Something {
    public function returnSomething(something:String, other:Int = 7):String;
}

…nothing changes:

lptr commented 11 years ago

One more thing: omitting the optional parameter like this:

m.returnSomething(cast anyString).returns("tibor");

…makes it break for both JS and Flash, regardless of the default value (0 or 7) of the optional parameter.

lptr commented 11 years ago

The only workaround I found right now is this:

var OPTIONAL_INT = #if flash 0 #else null #end;
m.returnSomething(cast anyString, OPTIONAL_INT).returns("tibor");

This way both JS and Flash compile, but it's ugly.

lptr commented 11 years ago

One more note: this doesn't work in JS, but works in Flash:

m.returnSomething(cast anyString, cast anyInt).returns("tibor");
misprintt commented 11 years ago

This is due to the differences on how default values are resolved on static and dynamic platforms (see http://haxe.org/manual/basic_types#statically-typed-platforms). Mockatoo detects if the platform is static or dynamic and ensures that valid 'nullified' values are used on optional function args.

In this case, the other arg is matching against null on js, and 0 on flash.

When the mock class is being generated at macro time, ClassField args (e.g. ?other:Int=0) dont expose the default value expr (e.g. 0), so I cant automatically use this value as the default across all platforms.

This limitation shouldn't matter for mocking anyway, as you should be matching on what is passed through, not what it defaults to internally when nullified.

To explicitly match across all platforms perhaps you should either use the any matcher

var m = Mockatoo.mock(Something);
assertThat(m.returnSomething("lajos"), is(null));
m.returnSomething(cast anyString,cast any).returns("tibor");
assertThat(m.returnSomething("lajos"), is("tibor"));

Or make the interface null safe across static and dynamic platforms

interface Something {
    public function returnSomething(something:String, ?other:Null<Int> = 0):String;
}

And then match explicitly against null

var m = Mockatoo.mock(Something);
assertThat(m.returnSomething("lajos"), is(null));
m.returnSomething(cast anyString,null).returns("tibor");
assertThat(m.returnSomething("lajos"), is("tibor"));
lptr commented 11 years ago

Thanks for the clarification. What you say makes sense for explicitly checking for the value. Maybe you could mention this in the Mockatoo documentation? Then it would make a lot of sense.

This limitation shouldn't matter for mocking anyway, as you should be matching on what is passed through, not what it defaults to internally when nullified.

As I wrote above in the first comment, this didn't work either:

m.returnSomething(cast anyString).returns("tibor");

Could Mockatoo inject any for any unspecified optional parameters to make it work?

misprintt commented 10 years ago

This is now implemented on master (only 7 months later!)