Browse Source

Merge pull request #129 from albyrock87/master

#128 : fixing exception on undefined index in IndexDescriptor
Sébastien Ros 10 years ago
parent
commit
7e7c935a89

+ 13 - 0
Jint.Tests/Runtime/InteropTests.cs

@@ -1111,5 +1111,18 @@ namespace Jint.Tests.Runtime
             ");
         }
 
+        [Fact]
+        public void ShouldReturnUndefinedProperty()
+        {
+            _engine.SetValue("uo", new { foo = "bar" });
+            _engine.SetValue("ud", new Dictionary<string, object>() { {"foo", "bar"} });
+            _engine.SetValue("ul", new List<string>() { "foo", "bar" });
+
+            RunTest(@"
+                assert(!uo.undefinedProperty);
+                assert(!ul[5]);
+                assert(!ud.undefinedProperty);
+            ");
+        }
     }
 }

+ 23 - 3
Jint/Runtime/Descriptors/Specialized/IndexDescriptor.cs

@@ -12,6 +12,7 @@ namespace Jint.Runtime.Descriptors.Specialized
         private readonly object _key;
         private readonly object _item;
         private readonly PropertyInfo _indexer;
+        private readonly MethodInfo _containsKey;
 
         public IndexDescriptor(Engine engine, Type targetType, string key, object item)
         {
@@ -20,12 +21,12 @@ namespace Jint.Runtime.Descriptors.Specialized
 
             // get all instance indexers with exactly 1 argument
             var indexers = targetType
-                .GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
-                .Where(x => x.GetIndexParameters().Length == 1);
+                .GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
 
             // try to find first indexer having either public getter or setter with matching argument type
             foreach (var indexer in indexers)
             {
+                if (indexer.GetIndexParameters().Length != 1) continue;
                 if (indexer.GetGetMethod() != null || indexer.GetSetMethod() != null)
                 {
                     var paramType = indexer.GetIndexParameters()[0].ParameterType;
@@ -33,6 +34,8 @@ namespace Jint.Runtime.Descriptors.Specialized
                     if (_engine.ClrTypeConverter.TryConvert(key, paramType, CultureInfo.InvariantCulture, out _key))
                     {
                         _indexer = indexer;
+                        // get contains key method to avoid index exception being thrown in dictionaries
+                        _containsKey = targetType.GetMethod("ContainsKey", new Type[] { paramType });
                         break;
 
                     }
@@ -59,13 +62,30 @@ namespace Jint.Runtime.Descriptors.Specialized
             get
             {
                 var getter = _indexer.GetGetMethod();
+
                 if (getter == null)
                 {
                     throw new InvalidOperationException("Indexer has no public getter.");
                 }
 
                 object[] parameters = { _key };
-                return JsValue.FromObject(_engine, getter.Invoke(_item, parameters));
+
+                if (_containsKey != null)
+                {
+                    if ((_containsKey.Invoke(_item, parameters) as bool?) != true)
+                    {
+                        return JsValue.Undefined;
+                    }
+                }
+                
+                try
+                {
+                    return JsValue.FromObject(_engine, getter.Invoke(_item, parameters));
+                }
+                catch
+                {
+                    return JsValue.Undefined;
+                }
             }
 
             set