Просмотр исходного кода

Fix smallest index handling against collection under interop (#1190)

Marko Lahma 3 лет назад
Родитель
Сommit
a5cf2f9f8d

+ 20 - 6
Jint.Tests/Runtime/InteropTests.cs

@@ -803,12 +803,12 @@ namespace Jint.Tests.Runtime
 
 
             Assert.Equal("A", _engine.Evaluate("obj.aProp"));
             Assert.Equal("A", _engine.Evaluate("obj.aProp"));
             Assert.Equal("B", _engine.Evaluate("obj.bProp"));
             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\"]", _engine.Evaluate("JSON.stringify(Object.getOwnPropertyNames(new ExtendedType()))"));
             // Assert.Equal("[\"a\",\"b\"]", _engine.Evaluate("JSON.stringify(Object.getOwnPropertyNames(new MyExtendedType()))"));
             // Assert.Equal("[\"a\",\"b\"]", _engine.Evaluate("JSON.stringify(Object.getOwnPropertyNames(new MyExtendedType()))"));
         }
         }
-        
+
         [Fact]
         [Fact]
         public void ShouldAllowMethodsOnClrExtendedTypes()
         public void ShouldAllowMethodsOnClrExtendedTypes()
         {
         {
@@ -846,7 +846,7 @@ namespace Jint.Tests.Runtime
             Assert.Equal(1, _engine.Evaluate("new ExtendsFromClr().getA();"));
             Assert.Equal(1, _engine.Evaluate("new ExtendsFromClr().getA();"));
             Assert.NotEqual(JsValue.Undefined, extendsFromClr.Get("getA"));
             Assert.NotEqual(JsValue.Undefined, extendsFromClr.Get("getA"));
         }
         }
-        
+
         private struct TestStruct
         private struct TestStruct
         {
         {
             public int Value;
             public int Value;
@@ -1353,7 +1353,7 @@ namespace Jint.Tests.Runtime
             var callCount = (int) _engine.GetValue("callCount").AsNumber();
             var callCount = (int) _engine.GetValue("callCount").AsNumber();
             Assert.Equal(1, callCount);
             Assert.Equal(1, callCount);
             Assert.Equal(2, collection.Count);
             Assert.Equal(2, collection.Count);
-            
+
             // make sure our delegate holder is hidden
             // make sure our delegate holder is hidden
             Assert.Equal("[]", _engine.Evaluate("json"));
             Assert.Equal("[]", _engine.Evaluate("json"));
         }
         }
@@ -2948,13 +2948,27 @@ namespace Jint.Tests.Runtime
         {
         {
             var engine = new Engine();
             var engine = new Engine();
             var mathTypeReference = TypeReference.CreateTypeReference(engine, typeof(Math));
             var mathTypeReference = TypeReference.CreateTypeReference(engine, typeof(Math));
-            
+
             engine.SetValue("Math2", mathTypeReference);
             engine.SetValue("Math2", mathTypeReference);
             var result = engine.Evaluate("Math2.Max(5.37, 5.56)").AsNumber();
             var result = engine.Evaluate("Math2.Max(5.37, 5.56)").AsNumber();
 
 
             Assert.Equal(5.56d, result);
             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
         private class Profile
         {
         {
             public int AnyProperty => throw new NotSupportedException("NOT SUPPORTED");
             public int AnyProperty => throw new NotSupportedException("NOT SUPPORTED");

+ 3 - 29
Jint/Native/Array/ArrayOperations.cs

@@ -158,33 +158,7 @@ namespace Jint.Native.Array
 
 
             public override ulong GetSmallestIndex(ulong length)
             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()
             public override uint GetLength()
@@ -294,10 +268,10 @@ namespace Jint.Native.Array
             public override void DeletePropertyOrThrow(ulong index)
             public override void DeletePropertyOrThrow(ulong index)
                 => _target.DeletePropertyOrThrow((uint) 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);
                 => _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);
                 => _target.SetIndexValue((uint) index, value, updateLength);
         }
         }
 
 

+ 31 - 0
Jint/Native/Object/ObjectInstance.cs

@@ -1380,5 +1380,36 @@ namespace Jint.Native.Object
         {
         {
             return TypeConverter.ToString(this);
             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;
+        }
     }
     }
 }
 }

+ 7 - 2
Jint/Runtime/Interop/ObjectWrapper.cs

@@ -73,7 +73,7 @@ namespace Jint.Runtime.Interop
             }
             }
             else if (property is JsSymbol jsSymbol)
             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)
                 if (_engine.Options.Interop.AllowWrite)
                 {
                 {
                     return base.Set(jsSymbol, value, receiver);
                     return base.Set(jsSymbol, value, receiver);
@@ -201,7 +201,7 @@ namespace Jint.Runtime.Interop
 
 
             // if type is dictionary, we cannot enumerate anything other than keys
             // if type is dictionary, we cannot enumerate anything other than keys
             // and we cannot store accessors as dictionary can change dynamically
             // and we cannot store accessors as dictionary can change dynamically
-            
+
             var isDictionary = _typeDescriptor.IsStringKeyedGenericDictionary;
             var isDictionary = _typeDescriptor.IsStringKeyedGenericDictionary;
             if (isDictionary)
             if (isDictionary)
             {
             {
@@ -259,6 +259,11 @@ namespace Jint.Runtime.Interop
             return JsNumber.Create((int) wrapper._typeDescriptor.LengthProperty.GetValue(wrapper.Target));
             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)
         public override bool Equals(JsValue? obj)
         {
         {
             return Equals(obj as ObjectWrapper);
             return Equals(obj as ObjectWrapper);