Skip to content

Commit

Permalink
Fix smallest index handling against collection under interop (#1190)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma committed Jun 6, 2022
1 parent 59dc54d commit a5cf2f9
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 37 deletions.
26 changes: 20 additions & 6 deletions Jint.Tests/Runtime/InteropTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -803,12 +803,12 @@ public void JavaScriptClassCanExtendClrType()

Assert.Equal("A", _engine.Evaluate("obj.aProp"));
Assert.Equal("B", _engine.Evaluate("obj.bProp"));
// TODO we should have a special prototype based on wrapped type so we could differentiate between own and type properties

// TODO we should have a special prototype based on wrapped type so we could differentiate between own and type properties
// Assert.Equal("[\"a\"]", _engine.Evaluate("JSON.stringify(Object.getOwnPropertyNames(new ExtendedType()))"));
// Assert.Equal("[\"a\",\"b\"]", _engine.Evaluate("JSON.stringify(Object.getOwnPropertyNames(new MyExtendedType()))"));
}

[Fact]
public void ShouldAllowMethodsOnClrExtendedTypes()
{
Expand Down Expand Up @@ -846,7 +846,7 @@ class ExtendsFromClr extends ClrBaseType {
Assert.Equal(1, _engine.Evaluate("new ExtendsFromClr().getA();"));
Assert.NotEqual(JsValue.Undefined, extendsFromClr.Get("getA"));
}

private struct TestStruct
{
public int Value;
Expand Down Expand Up @@ -1353,7 +1353,7 @@ public void ShouldExecuteActionCallbackOnEventChanged()
var callCount = (int) _engine.GetValue("callCount").AsNumber();
Assert.Equal(1, callCount);
Assert.Equal(2, collection.Count);

// make sure our delegate holder is hidden
Assert.Equal("[]", _engine.Evaluate("json"));
}
Expand Down Expand Up @@ -2948,13 +2948,27 @@ public void ShouldScoreDoubleToDoubleParameterMatchHigherThanDoubleToFloat()
{
var engine = new Engine();
var mathTypeReference = TypeReference.CreateTypeReference(engine, typeof(Math));

engine.SetValue("Math2", mathTypeReference);
var result = engine.Evaluate("Math2.Max(5.37, 5.56)").AsNumber();

Assert.Equal(5.56d, result);
}

[Fact]
public void ArrayPrototypeIndexOfWithInteropList()
{
var engine = new Jint.Engine();

engine.SetValue("list", new List<string> { "A", "B", "C" });

Assert.Equal(1, engine.Evaluate("list.indexOf('B')"));
Assert.Equal(1, engine.Evaluate("list.lastIndexOf('B')"));

Assert.Equal(1, engine.Evaluate("Array.prototype.indexOf.call(list, 'B')"));
Assert.Equal(1, engine.Evaluate("Array.prototype.lastIndexOf.call(list, 'B')"));
}

private class Profile
{
public int AnyProperty => throw new NotSupportedException("NOT SUPPORTED");
Expand Down
32 changes: 3 additions & 29 deletions Jint/Native/Array/ArrayOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,33 +158,7 @@ private double GetIntegerLength()

public override ulong GetSmallestIndex(ulong length)
{
// there are some evil tests that iterate a lot with unshift..
if (_target.Properties == null)
{
return 0;
}

var min = length;
foreach (var entry in _target.Properties)
{
if (ulong.TryParse(entry.Key.ToString(), out var index))
{
min = System.Math.Min(index, min);
}
}

if (_target.Prototype?.Properties != null)
{
foreach (var entry in _target.Prototype.Properties)
{
if (ulong.TryParse(entry.Key.ToString(), out var index))
{
min = System.Math.Min(index, min);
}
}
}

return min;
return _target.GetSmallestIndex(length);
}

public override uint GetLength()
Expand Down Expand Up @@ -294,10 +268,10 @@ public override JsValue[] GetAll(Types elementTypes)
public override void DeletePropertyOrThrow(ulong index)
=> _target.DeletePropertyOrThrow((uint) index);

public override void CreateDataPropertyOrThrow(ulong index, JsValue value)
public override void CreateDataPropertyOrThrow(ulong index, JsValue value)
=> _target.SetIndexValue((uint) index, value, updateLength: false);

public override void Set(ulong index, JsValue value, bool updateLength = false, bool throwOnError = true)
public override void Set(ulong index, JsValue value, bool updateLength = false, bool throwOnError = true)
=> _target.SetIndexValue((uint) index, value, updateLength);
}

Expand Down
31 changes: 31 additions & 0 deletions Jint/Native/Object/ObjectInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1380,5 +1380,36 @@ public override string ToString()
{
return TypeConverter.ToString(this);
}

internal virtual ulong GetSmallestIndex(ulong length)
{
// there are some evil tests that iterate a lot with unshift..
if (Properties == null)
{
return 0;
}

var min = length;
foreach (var entry in Properties)
{
if (ulong.TryParse(entry.Key.ToString(), out var index))
{
min = System.Math.Min(index, min);
}
}

if (Prototype?.Properties != null)
{
foreach (var entry in Prototype.Properties)
{
if (ulong.TryParse(entry.Key.ToString(), out var index))
{
min = System.Math.Min(index, min);
}
}
}

return min;
}
}
}
9 changes: 7 additions & 2 deletions Jint/Runtime/Interop/ObjectWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public override bool Set(JsValue property, JsValue value, JsValue receiver)
}
else if (property is JsSymbol jsSymbol)
{
// symbol addition will never hit any known CLR object properties, so if write is allowed, allow writing symbols too
// symbol addition will never hit any known CLR object properties, so if write is allowed, allow writing symbols too
if (_engine.Options.Interop.AllowWrite)
{
return base.Set(jsSymbol, value, receiver);
Expand Down Expand Up @@ -201,7 +201,7 @@ public override PropertyDescriptor GetOwnProperty(JsValue property)

// if type is dictionary, we cannot enumerate anything other than keys
// and we cannot store accessors as dictionary can change dynamically

var isDictionary = _typeDescriptor.IsStringKeyedGenericDictionary;
if (isDictionary)
{
Expand Down Expand Up @@ -259,6 +259,11 @@ private static JsValue GetLength(JsValue thisObj, JsValue[] arguments)
return JsNumber.Create((int) wrapper._typeDescriptor.LengthProperty.GetValue(wrapper.Target));
}

internal override ulong GetSmallestIndex(ulong length)
{
return Target is ICollection ? 0 : base.GetSmallestIndex(length);
}

public override bool Equals(JsValue? obj)
{
return Equals(obj as ObjectWrapper);
Expand Down

0 comments on commit a5cf2f9

Please sign in to comment.