The different behavior of the exposed functions and properties

Mar 28, 2012 at 10:11 PM

Hello,

It seems that invocation/execution of the exposed function with different arguments (where conversion would be involved) differs from assigning some value to the exposed property. Let me illustrate it on the example:

 

public class ExposedObject : ObjectInstance
    {
    private bool _boolValue;
    public ExposedObject( ScriptEngine engine )
        : base( engine )
        {
        PopulateFunctions();
        PopulateFields();
        }

    [JSFunction( Name="echo" )]
    public bool echo( bool boolValue ) { return _boolValue = boolValue; }

    [JSProperty( Name="echoProperty", IsEnumerable = true, IsConfigurable = true)]
    public bool echoProperty { get { return _boolValue; } set { _boolValue =  value; } }
    }

[TestFixture]
public class when_dotnet_object_exposed
    {
    private ScriptEngine _engine;

    [SetUp]
    public void setup()
        {
        _engine = new ScriptEngine{ CompatibilityMode = CompatibilityMode.Latest, EnableExposedClrTypes = false };
        _engine.SetGlobalValue( "$", new ExposedObject( _engine ) );
        }

    public R execute_script<R>( string text )
        {
        var r = _engine.Evaluate( text );
        return (R)r;
        }

    [Test]
    public void test_that_function_can_be_invoked_with_different_arguments()
        {
        Assert.That( execute_script<bool>( "$.echo( true );" ), Is.True );
        Assert.That( execute_script<bool>( "$.echo( -2.3 );" ), Is.True );
        Assert.That( execute_script<bool>( "$.echo( 'aaabbb' );" ), Is.True );
        Assert.That( execute_script<bool>( "$.echo( NaN );" ), Is.False );
        }

    [Test]
    public void test_that_property_can_be_invoked_with_different_arguments()
        {
        Assert.That( execute_script<bool>( "$.echoProperty = true; $.echoProperty;" ), Is.True );
        Assert.That( execute_script<bool>( "$.echoProperty = -2.3; $.echoProperty;" ), Is.True );
        Assert.That( execute_script<bool>( "$.echoProperty = 'aaabbb'; $.echoProperty;" ), Is.True );
        Assert.That( execute_script<bool>( "$.echoProperty = NaN; $.echoProperty;" ), Is.False );
        }
    }

I expect that both tests will be success but second one failed with exception:
test_that_property_can_be_invoked_with_different_arguments : 
    FailedJurassic.JavaScriptException : 
    TypeError: The best method overload Void set_echoProperty(Boolean) has some invalid arguments
at Jurassic.Compiler.BinderUtilities.ResolveOverloads(RuntimeMethodHandle[] methodHandles, ScriptEngine engine, Object thisValue, Object[] arguments)
at binder_for_ExposedObject.set_echoProperty(ScriptEngine, Object, Object[])
at Jurassic.Library.ObjectInstance.SetPropertyValueIfExists(String propertyName, Object value, Boolean throwOnError)
at Jurassic.Library.ObjectInstance.SetPropertyValue(String propertyName, Object value, Boolean throwOnError)
at Jurassic.Library.ObjectInstance.InlineSetPropertyValue(String name, Object value, Boolean throwOnError, ref Int32 cachedIndex, ref Object cacheKey)
at eval(ScriptEngine, Scope, Object)
at Jurassic.Compiler.EvalMethodGenerator.Execute()
at Jurassic.ScriptEngine.Evaluate(ScriptSource source)
at when_dotnet_object_exposed.execute_script(String text)
at when_dotnet_object_exposed.test_that_property_can_be_invoked_with_different_arguments()

To me it looks like a bug. Could anybody confirm that? Or for some reason it is expected behavior?

Thanks!

AC

 

 

Coordinator
Mar 28, 2012 at 11:04 PM

Looks like a bug to me too!  [JsProperty] is not used within Jurassic, and was never documented, so it's not really surprising (to me at least!) that it has issues.  I'll look into it.

Mar 29, 2012 at 1:57 AM
Edited Mar 29, 2012 at 2:00 AM

paulbartrum,

thanks for response! BTW it's good library and we are going to stick with it in our projects.

Currently I work around it by changing signature of the property as object echoProperty {get; set;} and writing converter from object to bool.

...
[JSProperty( Name="echoProperty", IsEnumerable = true, IsConfigurable = true)]
public object echoProperty 
    { 
    get { return _boolValue; } 
    set { _boolValue = toBool( value ); }
    }
    
private bool toBool( object value )
    {
    if ( value == null || value is Null || value is Undefined )
        return false;
    if ( value is bool )
        return (bool) value;
    if ( value is int )
        return ((int) value) != 0;
    if ( value is string )
        return !string.IsNullOrEmpty( (string) value );
    if ( value is double )
        return !double.IsNaN( (double) value );
    return true;
    }
...

Coordinator
Mar 29, 2012 at 2:37 AM

Yep, that works.  You could also use Jurassic.TypeConverter.ToBoolean() to do the conversion - it catches a few cases that your conversion method does not.

Mar 29, 2012 at 6:41 PM

paulbartrum,

Thanks for pointing me to Jurassic.TypeConverter, it is really handy.

My workarond does not work in case undefined value. The following code failed with same error even the property is specified as object.

...
[Test]
public void test_that_property_can_be_invoked_with_undefined_argument()
    {
    Assert.That( execute_script<bool>( "$.echoProperty = undefined; $.echoProperty;" ), Is.False );
    }
...

do you think I should open the issues related to the topic?

Coordinator
Apr 6, 2012 at 12:50 PM

I have checked in a fix for this issue.