/ API / tests / CustomGlobalObjectClassTest.c
CustomGlobalObjectClassTest.c
  1  /*
  2   * Copyright (C) 2014 Apple Inc. All rights reserved.
  3   *
  4   * Redistribution and use in source and binary forms, with or without
  5   * modification, are permitted provided that the following conditions
  6   * are met:
  7   * 1. Redistributions of source code must retain the above copyright
  8   *    notice, this list of conditions and the following disclaimer.
  9   * 2. Redistributions in binary form must reproduce the above copyright
 10   *    notice, this list of conditions and the following disclaimer in the
 11   *    documentation and/or other materials provided with the distribution.
 12   *
 13   * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 17   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24   */
 25  
 26  #include "config.h"
 27  #include "CustomGlobalObjectClassTest.h"
 28  
 29  #include <JavaScriptCore/JSObjectRefPrivate.h>
 30  #include <JavaScriptCore/JavaScript.h>
 31  #include <stdio.h>
 32  #include <stdlib.h>
 33  #include <string.h>
 34  
 35  extern bool assertTrue(bool value, const char* message);
 36  
 37  static bool executedCallback = false;
 38  
 39  static JSValueRef jsDoSomething(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argc, const JSValueRef args[], JSValueRef* exception)
 40  {
 41      (void)function;
 42      (void)thisObject;
 43      (void)argc;
 44      (void)args;
 45      (void)exception;
 46      executedCallback = true;
 47      return JSValueMakeNull(ctx);
 48  }
 49  
 50  static JSStaticFunction bridgedFunctions[] = {
 51      {"doSomething", jsDoSomething, kJSPropertyAttributeDontDelete},
 52      {0, 0, 0},
 53  };
 54  
 55  static JSClassRef bridgedObjectClass = NULL;
 56  static JSClassDefinition bridgedClassDef;
 57  
 58  static JSClassRef jsClassRef()
 59  {
 60      if (!bridgedObjectClass) {
 61          bridgedClassDef = kJSClassDefinitionEmpty;
 62          bridgedClassDef.className = "BridgedObject";
 63          bridgedClassDef.staticFunctions = bridgedFunctions;
 64          bridgedObjectClass = JSClassCreate(&bridgedClassDef);
 65      }
 66      return bridgedObjectClass;
 67  }
 68  
 69  void customGlobalObjectClassTest()
 70  {
 71      JSClassRef bridgedObjectJsClassRef = jsClassRef();
 72      JSGlobalContextRef globalContext = JSGlobalContextCreate(bridgedObjectJsClassRef);
 73      
 74      JSObjectRef globalObj = JSContextGetGlobalObject(globalContext);
 75      
 76      JSPropertyNameArrayRef propertyNames = JSObjectCopyPropertyNames(globalContext, globalObj);
 77      size_t propertyCount = JSPropertyNameArrayGetCount(propertyNames);
 78      assertTrue(propertyCount == 1, "Property count == 1");
 79      
 80      JSStringRef propertyNameRef = JSPropertyNameArrayGetNameAtIndex(propertyNames, 0);
 81      size_t propertyNameLength = JSStringGetLength(propertyNameRef);
 82      size_t bufferSize = sizeof(char) * (propertyNameLength + 1);
 83      char* buffer = (char*)malloc(bufferSize);
 84      JSStringGetUTF8CString(propertyNameRef, buffer, bufferSize);
 85      buffer[propertyNameLength] = '\0';
 86      assertTrue(!strncmp(buffer, "doSomething", propertyNameLength), "First property name is doSomething");
 87      free(buffer);
 88      
 89      bool hasMethod = JSObjectHasProperty(globalContext, globalObj, propertyNameRef);
 90      assertTrue(hasMethod, "Property found by name");
 91      
 92      JSValueRef doSomethingProperty =
 93      JSObjectGetProperty(globalContext, globalObj, propertyNameRef, NULL);
 94      assertTrue(!JSValueIsUndefined(globalContext, doSomethingProperty), "Property is defined");
 95      
 96      bool globalObjectClassMatchesClassRef = JSValueIsObjectOfClass(globalContext, globalObj, bridgedObjectJsClassRef);
 97      assertTrue(globalObjectClassMatchesClassRef, "Global object is the right class");
 98      
 99      JSStringRef script = JSStringCreateWithUTF8CString("doSomething();");
100      JSEvaluateScript(globalContext, script, NULL, NULL, 1, NULL);
101      JSStringRelease(script);
102  
103      assertTrue(executedCallback, "Executed custom global object callback");
104  
105      JSGlobalContextRelease(globalContext);
106  }
107  
108  void globalObjectSetPrototypeTest()
109  {
110      JSClassDefinition definition = kJSClassDefinitionEmpty;
111      definition.className = "Global";
112      JSClassRef global = JSClassCreate(&definition);
113      JSGlobalContextRef context = JSGlobalContextCreate(global);
114      JSObjectRef object = JSContextGetGlobalObject(context);
115  
116      JSValueRef originalPrototype = JSObjectGetPrototype(context, object);
117      JSObjectRef above = JSObjectMake(context, 0, 0);
118      JSObjectSetPrototype(context, object, above);
119      JSValueRef prototypeAfterChangingAttempt = JSObjectGetPrototype(context, object);
120      assertTrue(JSValueIsStrictEqual(context, prototypeAfterChangingAttempt, originalPrototype), "Global object's [[Prototype]] cannot be changed after instantiating it");
121      JSGlobalContextRelease(context);
122  }
123  
124  void globalObjectPrivatePropertyTest()
125  {
126      JSClassDefinition definition = kJSClassDefinitionEmpty;
127      definition.className = "Global";
128      JSClassRef global = JSClassCreate(&definition);
129      JSGlobalContextRef context = JSGlobalContextCreate(global);
130      JSObjectRef globalObject = JSContextGetGlobalObject(context);
131  
132      JSStringRef privateName = JSStringCreateWithUTF8CString("private");
133      JSValueRef privateValue = JSValueMakeString(context, privateName);
134      assertTrue(JSObjectSetPrivateProperty(context, globalObject, privateName, privateValue), "JSObjectSetPrivateProperty succeeded");
135      JSValueRef result = JSObjectGetPrivateProperty(context, globalObject, privateName);
136      assertTrue(JSValueIsStrictEqual(context, privateValue, result), "privateValue === \"private\"");
137  
138      assertTrue(JSObjectDeletePrivateProperty(context, globalObject, privateName), "JSObjectDeletePrivateProperty succeeded");
139      result = JSObjectGetPrivateProperty(context, globalObject, privateName);
140      assertTrue(JSValueIsNull(context, result), "Deleted private property is indeed no longer present");
141  
142      JSStringRelease(privateName);
143      JSGlobalContextRelease(context);
144  }