public void SetUp() { TestMethod method = TestExecutionContext.CurrentContext.CurrentTest as TestMethod; RuntimeFunctionInjectionAttribute attribute = method.Method.GetCustomAttributes <RuntimeFunctionInjectionAttribute>(false).FirstOrDefault(); if (attribute != null) { EcmaPropertyDescriptor descriptor = null; RuntimeFunction function = null; if (attribute.Type != 0) { RuntimeObject obj = RuntimeRealm.Current.GetRuntimeObject(attribute.Type); descriptor = obj.GetOwnProperty(attribute.Name); _ = obj; } else { string typeName = method.TypeInfo.Name; if (typeName.EndsWith("Object")) { typeName = typeName.Substring(0, typeName.Length - 6); } object objectType; if (Enum.TryParse(typeof(WellKnownObject), typeName, out objectType) || Enum.TryParse(typeof(WellKnownObject), typeName.Replace("Constructor", ""), out objectType)) { RuntimeObject obj = RuntimeRealm.Current.GetRuntimeObject((WellKnownObject)objectType); if (method.MethodName == "Constructor") { function = (RuntimeFunction)obj; _ = Global.GlobalThis; } else { descriptor = obj.GetOwnProperty(Regex.Replace(method.MethodName, "^[A-Z](?=[a-z])", v => v.Value.ToLower())); if (descriptor == null && Enum.TryParse(typeof(WellKnownSymbol), method.MethodName, out object sym)) { descriptor = obj.GetOwnProperty((WellKnownSymbol)sym); } _ = obj; } } } if (descriptor != null) { function = (descriptor.IsDataDescriptor ? descriptor.Value : descriptor.Get).GetUnderlyingObject() as RuntimeFunction; } TestContext.CurrentContext.Test.Arguments[0] = function; } }
protected override void WriteObjectBody(RuntimeObject obj) { foreach (EcmaPropertyKey propertyKey in obj.GetOwnPropertyKeys()) { EcmaPropertyDescriptor descriptor = obj.GetOwnProperty(propertyKey); if (descriptor != null && descriptor.IsDataDescriptor && descriptor.Enumerable) { WriteProperty(propertyKey, descriptor); } } }
protected virtual void WriteArray(RuntimeObject obj) { WriteToken(InspectorTokenType.ArrayStart); try { long length = obj[WellKnownProperty.Length].ToLength(); long prevIndex = -1; foreach (EcmaPropertyKey propertyKey in obj.GetOwnPropertyKeys()) { EcmaPropertyDescriptor descriptor = obj.GetOwnProperty(propertyKey); if (descriptor == null) { continue; } long index = propertyKey.IsArrayIndex ? propertyKey.ToArrayIndex() : -1; if (index >= 0 && index < length) { if (index > prevIndex + 1) { WriteArrayElision(index - prevIndex - 1); } WriteArrayItem(propertyKey, descriptor); prevIndex = index; } else { if (length > prevIndex + 1) { WriteArrayElision(length - prevIndex - 1); } prevIndex = length; if (descriptor.Enumerable) { WriteProperty(propertyKey, descriptor); } } if (this.LastToken == InspectorTokenType.Ellipsis) { prevIndex = length; break; } } if (length > prevIndex + 1) { WriteArrayElision(length - prevIndex - 1); } } catch { WriteToken(InspectorTokenType.Ellipsis); } WriteToken(InspectorTokenType.ArrayEnd); }
public void ObjectHosting() { It("should return different instances on different execution thread", () => { TestObject obj = new TestObject(); RuntimeObject v0 = RuntimeRealm.Current.ResolveRuntimeObject(obj); RuntimeExecution.CreateWorkerThread(parentRealm => { Assume.That(parentRealm, Is.Not.EqualTo(RuntimeRealm.Current), "realm should be different"); RuntimeObject v1 = RuntimeRealm.Current.ResolveRuntimeObject(obj); That(v0 != v1, "returned object should be different"); That(v0.Realm, Is.EqualTo(parentRealm)); That(v1.Realm, Is.EqualTo(RuntimeRealm.Current)); That(v0.GetPrototypeOf() != v1.GetPrototypeOf(), "the prototype of returned object should be different"); That(v0.GetPrototypeOf().Realm, Is.EqualTo(parentRealm)); That(v1.GetPrototypeOf().Realm, Is.EqualTo(RuntimeRealm.Current)); That(v0.GetPrototypeOf().GetPrototypeOf() != v1.GetPrototypeOf().GetPrototypeOf(), "all prototype ancestors of returned object should be different"); That(v0["MyMethod"], Is.TypeOf("function")); That(v0["MyMethod"], Is.Not.EqualTo(v1["MyMethod"]), "property value of object type should be different"); }, true).Thread.Join(); }); It("should return different instances on different realm of the same execution thread", () => { TestObject obj = new TestObject(); RuntimeObject v0 = RuntimeRealm.Current.ResolveRuntimeObject(obj); RuntimeRealm parentRealm = RuntimeRealm.Current; RuntimeRealm other = new RuntimeRealm(); other.Enqueue(() => { Assume.That(RuntimeRealm.Current, Is.Not.EqualTo(parentRealm), "realm should be different"); Assume.That(RuntimeRealm.Current, Is.EqualTo(other)); RuntimeObject v1 = RuntimeRealm.Current.ResolveRuntimeObject(obj); That(v0 != v1, "returned object should be different"); That(v0.Realm, Is.EqualTo(parentRealm)); That(v1.Realm, Is.EqualTo(RuntimeRealm.Current)); That(v0.GetPrototypeOf() != v1.GetPrototypeOf(), "the prototype of returned object should be different"); That(v0.GetPrototypeOf().Realm, Is.EqualTo(parentRealm)); That(v1.GetPrototypeOf().Realm, Is.EqualTo(RuntimeRealm.Current)); That(v0.GetPrototypeOf().GetPrototypeOf() != v1.GetPrototypeOf().GetPrototypeOf(), "all prototype ancestors of returned object should be different"); That(v0["MyMethod"], Is.TypeOf("function")); That(v0["MyMethod"], Is.Not.EqualTo(v1["MyMethod"]), "property value of object type should be different"); }); RuntimeExecution.ContinueUntilEnd(); }); It("should expose native properties as getters and setters on protoype", () => { TestObject obj = new TestObject(); EcmaValue value = new EcmaValue(obj); value["Value"] = 1; That(value["Value"], Is.EqualTo(1)); That(obj.Value, Is.EqualTo(1), "Value should be reflected on native object"); That(() => value["ReadOnlyValue"] = 2, Throws.Nothing, "Setting a readonly property does not throw exception"); That(value["ReadOnlyValue"], Is.EqualTo(1), "Value should not be changed"); RuntimeObject testObjectPrototype = value.ToObject().GetPrototypeOf(); That(testObjectPrototype.GetOwnProperty("Value"), Is.Not.EqualTo(EcmaValue.Undefined), "Property should be defined on the reflected prototype object"); That(testObjectPrototype.GetOwnProperty("Value").Get, Is.Not.EqualTo(EcmaValue.Undefined), "Property should be defined as getter/setter"); That(testObjectPrototype.GetOwnProperty("ReadOnlyValue").Set, Is.Undefined, "Readonly property should have no setter"); }); It("should expose IList as an Array exotic object", () => { EcmaValue list = new EcmaValue(new List <object> { 1, 2, 3, new EcmaObject() }); That(list["length"], Is.EqualTo(4)); That(list.ToString(), Is.EqualTo("1,2,3,[object Object]")); That(Global.Json.Invoke("stringify", list), Is.EqualTo("[1,2,3,{}]")); }); It("should expose IDictionary as an ordinary object for valid EcmaPropertyKey", () => { Hashtable ht = new Hashtable(); EcmaValue obj = new EcmaValue(ht); obj["prop"] = 1; That(obj["prop"], Is.EqualTo(1)); That(Global.Json.Invoke("stringify", obj), Is.EqualTo("{\"prop\":1}")); }); }
public InspectorMetaObject(RuntimeObject obj) { Guard.ArgumentNotNull(obj, "obj"); this.EnumerableProperties = new InspectorMetaObjectEntryCollection(); this.NonEnumerableProperties = new InspectorMetaObjectEntryCollection(); if (!(obj is RuntimeObjectProxy)) { this.Prototype = new EcmaValue(obj.GetPrototypeOf()); if (this.Prototype.IsNullOrUndefined) { this.Prototype = EcmaValue.Null; } for (RuntimeObject cur = obj; cur != null; cur = cur.GetPrototypeOf()) { foreach (EcmaPropertyKey property in cur.GetOwnPropertyKeys()) { EcmaPropertyDescriptor descriptor = cur.GetOwnProperty(property); if (descriptor == null || (descriptor.IsDataDescriptor && cur != obj)) { continue; } EcmaValue value; if (descriptor.IsDataDescriptor) { value = descriptor.Value; } else { try { value = descriptor.Get.Call(obj); } catch (EcmaException ex) { value = String.Format("{0}: {1}", ex.ErrorType, ex.Message); } catch (Exception ex) { value = ex.Message; } if (cur == obj) { if (descriptor.Get) { NonEnumerableProperties.Add("get " + property, descriptor.Get); } if (descriptor.Set) { NonEnumerableProperties.Add("set " + property, descriptor.Get); } } } if (descriptor.Enumerable) { EnumerableProperties.Add(property, value); } else { NonEnumerableProperties.Add(property, value); } } } } if (obj is IInspectorMetaProvider provider) { try { provider.FillInInspectorMetaObject(this); } catch { } } }