source: webkit/trunk/JavaScriptCore/API/testapi.c@ 15310

Last change on this file since 15310 was 15310, checked in by ggaren, 19 years ago

Reviewed by Darin.

Improved type safety by implementing opaque JSValue/JSObject typing through
abuse of 'const', not void*. Also fixed an alarming number of bugs
exposed by this new type safety.


I made one design change in JavaScriptCore, which is that the JSObject
constructor should take a JSValue* as its prototype argument, not a JSObject*,
since we allow the prototype to be any JSValue*, including jsNull(), for
example.


  • API/APICast.h: (toJS):
  • API/JSBase.h:
  • API/JSCallbackConstructor.cpp: (KJS::JSCallbackConstructor::construct):
  • API/JSCallbackFunction.cpp: (KJS::JSCallbackFunction::callAsFunction):
  • API/JSCallbackObject.cpp: (KJS::JSCallbackObject::JSCallbackObject): (KJS::JSCallbackObject::getOwnPropertySlot): (KJS::JSCallbackObject::put): (KJS::JSCallbackObject::construct): (KJS::JSCallbackObject::callAsFunction): (KJS::JSCallbackObject::staticFunctionGetter):
  • API/JSCallbackObject.h:
  • API/JSContextRef.cpp: (JSEvaluate):
  • API/JSNode.c: (JSNodePrototype_appendChild): (JSNodePrototype_removeChild): (JSNodePrototype_replaceChild):
  • API/JSObjectRef.cpp: (JSObjectMake): (JSFunctionMakeWithBody): (JSObjectGetProperty): (JSObjectCallAsFunction): (JSObjectCallAsConstructor):
  • API/JSObjectRef.h:
  • API/testapi.c: (main):
  • ChangeLog:
  • kjs/object.h: (KJS::JSObject::JSObject):
File size: 25.6 KB
Line 
1// -*- mode: c++; c-basic-offset: 4 -*-
2/*
3 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "JavaScriptCore.h"
28#include <wtf/UnusedParam.h>
29
30#if defined(__APPLE__)
31#include <CoreFoundation/CoreFoundation.h>
32#endif
33
34#include <assert.h>
35#include <math.h>
36
37static JSContextRef context = 0;
38
39static void assertEqualsAsBoolean(JSValueRef value, bool expectedValue)
40{
41 if (JSValueToBoolean(context, value) != expectedValue)
42 fprintf(stderr, "assertEqualsAsBoolean failed: %p, %d\n", value, expectedValue);
43}
44
45static void assertEqualsAsNumber(JSValueRef value, double expectedValue)
46{
47 double number = JSValueToNumber(context, value);
48 if (number != expectedValue && !(isnan(number) && isnan(expectedValue)))
49 fprintf(stderr, "assertEqualsAsNumber failed: %p, %lf\n", value, expectedValue);
50}
51
52static void assertEqualsAsUTF8String(JSValueRef value, const char* expectedValue)
53{
54 JSInternalStringRef valueAsString = JSValueCopyStringValue(context, value);
55
56 size_t jsSize = JSInternalStringGetMaxLengthUTF8(valueAsString);
57 char jsBuffer[jsSize];
58 JSInternalStringGetCharactersUTF8(valueAsString, jsBuffer, jsSize);
59
60 if (strcmp(jsBuffer, expectedValue) != 0)
61 fprintf(stderr, "assertEqualsAsUTF8String strcmp failed: %s != %s\n", jsBuffer, expectedValue);
62
63 if (jsSize < strlen(jsBuffer) + 1)
64 fprintf(stderr, "assertEqualsAsUTF8String failed: jsSize was too small\n");
65
66 JSInternalStringRelease(valueAsString);
67}
68
69#if defined(__APPLE__)
70static void assertEqualsAsCharactersPtr(JSValueRef value, const char* expectedValue)
71{
72 JSInternalStringRef valueAsString = JSValueCopyStringValue(context, value);
73
74 size_t jsLength = JSInternalStringGetLength(valueAsString);
75 const JSChar* jsBuffer = JSInternalStringGetCharactersPtr(valueAsString);
76
77 CFStringRef expectedValueAsCFString = CFStringCreateWithCString(kCFAllocatorDefault,
78 expectedValue,
79 kCFStringEncodingUTF8);
80 CFIndex cfLength = CFStringGetLength(expectedValueAsCFString);
81 UniChar cfBuffer[cfLength];
82 CFStringGetCharacters(expectedValueAsCFString, CFRangeMake(0, cfLength), cfBuffer);
83 CFRelease(expectedValueAsCFString);
84
85 if (memcmp(jsBuffer, cfBuffer, cfLength * sizeof(UniChar)) != 0)
86 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsBuffer != cfBuffer\n");
87
88 if (jsLength != (size_t)cfLength)
89 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%ld) != cfLength(%ld)\n", jsLength, cfLength);
90
91 JSInternalStringRelease(valueAsString);
92}
93
94static void assertEqualsAsCharacters(JSValueRef value, const char* expectedValue)
95{
96 JSInternalStringRef valueAsString = JSValueCopyStringValue(context, value);
97
98 size_t jsLength = JSInternalStringGetLength(valueAsString);
99 JSChar jsBuffer[jsLength];
100 JSInternalStringGetCharacters(valueAsString, jsBuffer, jsLength);
101
102 CFStringRef expectedValueAsCFString = CFStringCreateWithCString(kCFAllocatorDefault,
103 expectedValue,
104 kCFStringEncodingUTF8);
105 CFIndex cfLength = CFStringGetLength(expectedValueAsCFString);
106 UniChar cfBuffer[cfLength];
107 CFStringGetCharacters(expectedValueAsCFString, CFRangeMake(0, cfLength), cfBuffer);
108 CFRelease(expectedValueAsCFString);
109
110 if (memcmp(jsBuffer, cfBuffer, cfLength * sizeof(UniChar)) != 0)
111 fprintf(stderr, "assertEqualsAsCharacters failed: jsBuffer != cfBuffer\n");
112
113 if (jsLength != (size_t)cfLength)
114 fprintf(stderr, "assertEqualsAsCharacters failed: jsLength(%ld) != cfLength(%ld)\n", jsLength, cfLength);
115
116 JSInternalStringRelease(valueAsString);
117}
118#endif // __APPLE__
119
120static JSValueRef jsGlobalValue; // non-stack value for testing JSGCProtect()
121
122/* MyObject pseudo-class */
123
124static bool didInitialize = false;
125static void MyObject_initialize(JSContextRef context, JSObjectRef object)
126{
127 UNUSED_PARAM(context);
128 UNUSED_PARAM(object);
129 didInitialize = true;
130}
131
132static bool MyObject_hasProperty(JSContextRef context, JSObjectRef object, JSInternalStringRef propertyName)
133{
134 UNUSED_PARAM(context);
135 UNUSED_PARAM(object);
136
137 if (JSInternalStringIsEqualUTF8(propertyName, "alwaysOne")
138 || JSInternalStringIsEqualUTF8(propertyName, "cantFind")
139 || JSInternalStringIsEqualUTF8(propertyName, "myPropertyName")) {
140 return true;
141 }
142
143 return false;
144}
145
146static bool MyObject_getProperty(JSContextRef context, JSObjectRef object, JSInternalStringRef propertyName, JSValueRef* returnValue)
147{
148 UNUSED_PARAM(context);
149 UNUSED_PARAM(object);
150
151 if (JSInternalStringIsEqualUTF8(propertyName, "alwaysOne")) {
152 *returnValue = JSNumberMake(1);
153 return true;
154 }
155
156 if (JSInternalStringIsEqualUTF8(propertyName, "myPropertyName")) {
157 *returnValue = JSNumberMake(1);
158 return true;
159 }
160
161 if (JSInternalStringIsEqualUTF8(propertyName, "cantFind")) {
162 *returnValue = JSUndefinedMake();
163 return true;
164 }
165
166 return false;
167}
168
169static bool MyObject_setProperty(JSContextRef context, JSObjectRef object, JSInternalStringRef propertyName, JSValueRef value)
170{
171 UNUSED_PARAM(context);
172 UNUSED_PARAM(object);
173 UNUSED_PARAM(value);
174
175 if (JSInternalStringIsEqualUTF8(propertyName, "cantSet"))
176 return true; // pretend we set the property in order to swallow it
177
178 return false;
179}
180
181static bool MyObject_deleteProperty(JSContextRef context, JSObjectRef object, JSInternalStringRef propertyName)
182{
183 UNUSED_PARAM(context);
184 UNUSED_PARAM(object);
185
186 if (JSInternalStringIsEqualUTF8(propertyName, "cantDelete"))
187 return true;
188
189 return false;
190}
191
192static void MyObject_getPropertyList(JSContextRef context, JSObjectRef object, JSPropertyListRef propertyList)
193{
194 UNUSED_PARAM(context);
195
196 JSInternalStringRef propertyNameBuf;
197
198 propertyNameBuf = JSInternalStringCreateUTF8("alwaysOne");
199 JSPropertyListAdd(propertyList, object, propertyNameBuf);
200 JSInternalStringRelease(propertyNameBuf);
201
202 propertyNameBuf = JSInternalStringCreateUTF8("myPropertyName");
203 JSPropertyListAdd(propertyList, object, propertyNameBuf);
204 JSInternalStringRelease(propertyNameBuf);
205}
206
207static JSValueRef MyObject_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argc, JSValueRef argv[])
208{
209 UNUSED_PARAM(context);
210 UNUSED_PARAM(object);
211 UNUSED_PARAM(thisObject);
212
213 if (argc > 0 && JSValueIsStrictEqual(context, argv[0], JSNumberMake(0)))
214 return JSNumberMake(1);
215
216 return JSUndefinedMake();
217}
218
219static JSObjectRef MyObject_callAsConstructor(JSContextRef context, JSObjectRef object, size_t argc, JSValueRef argv[])
220{
221 UNUSED_PARAM(context);
222 UNUSED_PARAM(object);
223
224 if (argc > 0 && JSValueIsStrictEqual(context, argv[0], JSNumberMake(0)))
225 return JSValueToObject(context, JSNumberMake(1));
226
227 return JSValueToObject(context, JSNumberMake(0));
228}
229
230static bool MyObject_convertToType(JSContextRef context, JSObjectRef object, JSTypeCode typeCode, JSValueRef* returnValue)
231{
232 UNUSED_PARAM(context);
233 UNUSED_PARAM(object);
234
235 switch (typeCode) {
236 case kJSTypeBoolean:
237 *returnValue = JSBooleanMake(false); // default object conversion is 'true'
238 return true;
239 case kJSTypeNumber:
240 *returnValue = JSNumberMake(1);
241 return true;
242 default:
243 break;
244 }
245
246 // string
247 return false;
248}
249
250static bool didFinalize = false;
251static void MyObject_finalize(JSObjectRef object)
252{
253 UNUSED_PARAM(context);
254 UNUSED_PARAM(object);
255 didFinalize = true;
256}
257
258JSObjectCallbacks MyObject_callbacks = {
259 0,
260 &MyObject_initialize,
261 &MyObject_finalize,
262 &MyObject_hasProperty,
263 &MyObject_getProperty,
264 &MyObject_setProperty,
265 &MyObject_deleteProperty,
266 &MyObject_getPropertyList,
267 &MyObject_callAsFunction,
268 &MyObject_callAsConstructor,
269 &MyObject_convertToType,
270};
271
272static JSClassRef MyObject_class(JSContextRef context)
273{
274 static JSClassRef jsClass;
275 if (!jsClass) {
276 jsClass = JSClassCreate(NULL, NULL, &MyObject_callbacks, NULL);
277 }
278
279 return jsClass;
280}
281
282static JSValueRef print_callAsFunction(JSContextRef context, JSObjectRef functionObject, JSObjectRef thisObject, size_t argc, JSValueRef argv[])
283{
284 UNUSED_PARAM(functionObject);
285 UNUSED_PARAM(thisObject);
286
287 if (argc > 0) {
288 JSInternalStringRef string = JSValueCopyStringValue(context, argv[0]);
289 size_t sizeUTF8 = JSInternalStringGetMaxLengthUTF8(string);
290 char stringUTF8[sizeUTF8];
291 JSInternalStringGetCharactersUTF8(string, stringUTF8, sizeUTF8);
292 printf("%s\n", stringUTF8);
293 JSInternalStringRelease(string);
294 }
295
296 return JSUndefinedMake();
297}
298
299static JSObjectRef myConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argc, JSValueRef argv[])
300{
301 UNUSED_PARAM(constructorObject);
302
303 JSObjectRef result = JSObjectMake(context, NULL, 0);
304 if (argc > 0) {
305 JSInternalStringRef valueBuffer = JSInternalStringCreateUTF8("value");
306 JSObjectSetProperty(context, result, valueBuffer, argv[0], kJSPropertyAttributeNone);
307 JSInternalStringRelease(valueBuffer);
308 }
309
310 return result;
311}
312
313static char* createStringWithContentsOfFile(const char* fileName);
314
315int main(int argc, char* argv[])
316{
317 UNUSED_PARAM(argc);
318 UNUSED_PARAM(argv);
319
320 context = JSContextCreate(NULL);
321
322 JSValueRef jsUndefined = JSUndefinedMake();
323 JSValueRef jsNull = JSNullMake();
324 JSValueRef jsTrue = JSBooleanMake(true);
325 JSValueRef jsFalse = JSBooleanMake(false);
326 JSValueRef jsZero = JSNumberMake(0);
327 JSValueRef jsOne = JSNumberMake(1);
328 JSValueRef jsOneThird = JSNumberMake(1.0 / 3.0);
329 JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, JSNullMake());
330
331 // FIXME: test funny utf8 characters
332 JSInternalStringRef jsEmptyStringBuf = JSInternalStringCreateUTF8("");
333 JSValueRef jsEmptyString = JSStringMake(jsEmptyStringBuf);
334
335 JSInternalStringRef jsOneStringBuf = JSInternalStringCreateUTF8("1");
336 JSValueRef jsOneString = JSStringMake(jsOneStringBuf);
337
338#if defined(__APPLE__)
339 UniChar singleUniChar = 65; // Capital A
340 CFMutableStringRef cfString =
341 CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault,
342 &singleUniChar,
343 1,
344 1,
345 kCFAllocatorNull);
346
347 JSInternalStringRef jsCFStringBuf = JSInternalStringCreateCF(cfString);
348 JSValueRef jsCFString = JSStringMake(jsCFStringBuf);
349
350 CFStringRef cfEmptyString = CFStringCreateWithCString(kCFAllocatorDefault, "", kCFStringEncodingUTF8);
351
352 JSInternalStringRef jsCFEmptyStringBuf = JSInternalStringCreateCF(cfEmptyString);
353 JSValueRef jsCFEmptyString = JSStringMake(jsCFEmptyStringBuf);
354
355 CFIndex cfStringLength = CFStringGetLength(cfString);
356 UniChar buffer[cfStringLength];
357 CFStringGetCharacters(cfString,
358 CFRangeMake(0, cfStringLength),
359 buffer);
360 JSInternalStringRef jsCFStringWithCharactersBuf = JSInternalStringCreate(buffer, cfStringLength);
361 JSValueRef jsCFStringWithCharacters = JSStringMake(jsCFStringWithCharactersBuf);
362
363 JSInternalStringRef jsCFEmptyStringWithCharactersBuf = JSInternalStringCreate(buffer, CFStringGetLength(cfEmptyString));
364 JSValueRef jsCFEmptyStringWithCharacters = JSStringMake(jsCFEmptyStringWithCharactersBuf);
365#endif // __APPLE__
366
367 assert(JSValueGetType(jsUndefined) == kJSTypeUndefined);
368 assert(JSValueGetType(jsNull) == kJSTypeNull);
369 assert(JSValueGetType(jsTrue) == kJSTypeBoolean);
370 assert(JSValueGetType(jsFalse) == kJSTypeBoolean);
371 assert(JSValueGetType(jsZero) == kJSTypeNumber);
372 assert(JSValueGetType(jsOne) == kJSTypeNumber);
373 assert(JSValueGetType(jsOneThird) == kJSTypeNumber);
374 assert(JSValueGetType(jsEmptyString) == kJSTypeString);
375 assert(JSValueGetType(jsOneString) == kJSTypeString);
376#if defined(__APPLE__)
377 assert(JSValueGetType(jsCFString) == kJSTypeString);
378 assert(JSValueGetType(jsCFStringWithCharacters) == kJSTypeString);
379 assert(JSValueGetType(jsCFEmptyString) == kJSTypeString);
380 assert(JSValueGetType(jsCFEmptyStringWithCharacters) == kJSTypeString);
381#endif // __APPLE__
382
383 // Conversions that throw exceptions
384 assert(NULL == JSValueToObject(context, jsNull));
385 assert(!JSContextGetException(context));
386 assert(isnan(JSValueToNumber(context, jsObjectNoProto)));
387 assert(!JSContextGetException(context));
388 assertEqualsAsCharactersPtr(jsObjectNoProto, "");
389 assert(!JSContextGetException(context));
390
391 assertEqualsAsBoolean(jsUndefined, false);
392 assertEqualsAsBoolean(jsNull, false);
393 assertEqualsAsBoolean(jsTrue, true);
394 assertEqualsAsBoolean(jsFalse, false);
395 assertEqualsAsBoolean(jsZero, false);
396 assertEqualsAsBoolean(jsOne, true);
397 assertEqualsAsBoolean(jsOneThird, true);
398 assertEqualsAsBoolean(jsEmptyString, false);
399 assertEqualsAsBoolean(jsOneString, true);
400#if defined(__APPLE__)
401 assertEqualsAsBoolean(jsCFString, true);
402 assertEqualsAsBoolean(jsCFStringWithCharacters, true);
403 assertEqualsAsBoolean(jsCFEmptyString, false);
404 assertEqualsAsBoolean(jsCFEmptyStringWithCharacters, false);
405#endif // __APPLE__
406
407 assertEqualsAsNumber(jsUndefined, nan(""));
408 assertEqualsAsNumber(jsNull, 0);
409 assertEqualsAsNumber(jsTrue, 1);
410 assertEqualsAsNumber(jsFalse, 0);
411 assertEqualsAsNumber(jsZero, 0);
412 assertEqualsAsNumber(jsOne, 1);
413 assertEqualsAsNumber(jsOneThird, 1.0 / 3.0);
414 assertEqualsAsNumber(jsEmptyString, 0);
415 assertEqualsAsNumber(jsOneString, 1);
416#if defined(__APPLE__)
417 assertEqualsAsNumber(jsCFString, nan(""));
418 assertEqualsAsNumber(jsCFStringWithCharacters, nan(""));
419 assertEqualsAsNumber(jsCFEmptyString, 0);
420 assertEqualsAsNumber(jsCFEmptyStringWithCharacters, 0);
421 assert(sizeof(JSChar) == sizeof(UniChar));
422#endif // __APPLE__
423
424 assertEqualsAsCharactersPtr(jsUndefined, "undefined");
425 assertEqualsAsCharactersPtr(jsNull, "null");
426 assertEqualsAsCharactersPtr(jsTrue, "true");
427 assertEqualsAsCharactersPtr(jsFalse, "false");
428 assertEqualsAsCharactersPtr(jsZero, "0");
429 assertEqualsAsCharactersPtr(jsOne, "1");
430 assertEqualsAsCharactersPtr(jsOneThird, "0.3333333333333333");
431 assertEqualsAsCharactersPtr(jsEmptyString, "");
432 assertEqualsAsCharactersPtr(jsOneString, "1");
433#if defined(__APPLE__)
434 assertEqualsAsCharactersPtr(jsCFString, "A");
435 assertEqualsAsCharactersPtr(jsCFStringWithCharacters, "A");
436 assertEqualsAsCharactersPtr(jsCFEmptyString, "");
437 assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters, "");
438#endif // __APPLE__
439
440 assertEqualsAsCharacters(jsUndefined, "undefined");
441 assertEqualsAsCharacters(jsNull, "null");
442 assertEqualsAsCharacters(jsTrue, "true");
443 assertEqualsAsCharacters(jsFalse, "false");
444 assertEqualsAsCharacters(jsZero, "0");
445 assertEqualsAsCharacters(jsOne, "1");
446 assertEqualsAsCharacters(jsOneThird, "0.3333333333333333");
447 assertEqualsAsCharacters(jsEmptyString, "");
448 assertEqualsAsCharacters(jsOneString, "1");
449#if defined(__APPLE__)
450 assertEqualsAsCharacters(jsCFString, "A");
451 assertEqualsAsCharacters(jsCFStringWithCharacters, "A");
452 assertEqualsAsCharacters(jsCFEmptyString, "");
453 assertEqualsAsCharacters(jsCFEmptyStringWithCharacters, "");
454#endif // __APPLE__
455
456 assertEqualsAsUTF8String(jsUndefined, "undefined");
457 assertEqualsAsUTF8String(jsNull, "null");
458 assertEqualsAsUTF8String(jsTrue, "true");
459 assertEqualsAsUTF8String(jsFalse, "false");
460 assertEqualsAsUTF8String(jsZero, "0");
461 assertEqualsAsUTF8String(jsOne, "1");
462 assertEqualsAsUTF8String(jsOneThird, "0.3333333333333333");
463 assertEqualsAsUTF8String(jsEmptyString, "");
464 assertEqualsAsUTF8String(jsOneString, "1");
465#if defined(__APPLE__)
466 assertEqualsAsUTF8String(jsCFString, "A");
467 assertEqualsAsUTF8String(jsCFStringWithCharacters, "A");
468 assertEqualsAsUTF8String(jsCFEmptyString, "");
469 assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters, "");
470#endif // __APPLE__
471
472 assert(JSValueIsStrictEqual(context, jsTrue, jsTrue));
473 assert(!JSValueIsStrictEqual(context, jsOne, jsOneString));
474
475 assert(JSValueIsEqual(context, jsOne, jsOneString));
476 assert(!JSValueIsEqual(context, jsTrue, jsFalse));
477
478#if defined(__APPLE__)
479 CFStringRef cfJSString = CFStringCreateWithJSInternalString(kCFAllocatorDefault, jsCFStringBuf);
480 CFStringRef cfJSEmptyString = CFStringCreateWithJSInternalString(kCFAllocatorDefault, jsCFEmptyStringBuf);
481 assert(CFEqual(cfJSString, cfString));
482 assert(CFEqual(cfJSEmptyString, cfEmptyString));
483 CFRelease(cfJSString);
484 CFRelease(cfJSEmptyString);
485
486 CFRelease(cfString);
487 CFRelease(cfEmptyString);
488#endif // __APPLE__
489
490 jsGlobalValue = JSObjectMake(context, NULL, NULL);
491 JSGCProtect(jsGlobalValue);
492 JSGCCollect();
493 assert(JSValueIsObject(jsGlobalValue));
494 JSGCUnprotect(jsGlobalValue);
495
496 /* JSInterpreter.h */
497
498 JSObjectRef globalObject = JSContextGetGlobalObject(context);
499 assert(JSValueIsObject(globalObject));
500
501 JSInternalStringRef goodSyntaxBuf = JSInternalStringCreateUTF8("x = 1;");
502 JSInternalStringRef badSyntaxBuf = JSInternalStringCreateUTF8("x := 1;");
503 assert(JSCheckSyntax(context, goodSyntaxBuf, NULL, 0, NULL));
504 assert(!JSCheckSyntax(context, badSyntaxBuf, NULL, 0, NULL));
505
506 JSValueRef result;
507 JSValueRef exception;
508 JSValueRef v;
509 JSObjectRef o;
510
511 result = JSEvaluate(context, goodSyntaxBuf, NULL, NULL, 1, NULL);
512 assert(result);
513 assert(JSValueIsEqual(context, result, jsOne));
514
515 exception = NULL;
516 result = JSEvaluate(context, badSyntaxBuf, NULL, NULL, 1, &exception);
517 assert(!result);
518 assert(!JSContextGetException(context));
519 assert(JSValueIsObject(exception));
520
521 JSContextSetException(context, JSNumberMake(1));
522 assert(JSContextGetException(context));
523 assert(JSValueIsEqual(context, jsOne, JSContextGetException(context)));
524 JSContextClearException(context);
525 assert(!JSContextGetException(context));
526
527 JSInternalStringRelease(jsEmptyStringBuf);
528 JSInternalStringRelease(jsOneStringBuf);
529#if defined(__APPLE__)
530 JSInternalStringRelease(jsCFStringBuf);
531 JSInternalStringRelease(jsCFEmptyStringBuf);
532 JSInternalStringRelease(jsCFStringWithCharactersBuf);
533 JSInternalStringRelease(jsCFEmptyStringWithCharactersBuf);
534#endif // __APPLE__
535 JSInternalStringRelease(goodSyntaxBuf);
536 JSInternalStringRelease(badSyntaxBuf);
537
538 JSInternalStringRef arrayBuf = JSInternalStringCreateUTF8("Array");
539 v = JSObjectGetProperty(context, globalObject, arrayBuf);
540 assert(v);
541 JSObjectRef arrayConstructor = JSValueToObject(context, v);
542 JSInternalStringRelease(arrayBuf);
543 result = JSObjectCallAsConstructor(context, arrayConstructor, 0, NULL, NULL);
544 assert(result);
545 assert(JSValueIsInstanceOf(context, result, arrayConstructor));
546 assert(!JSValueIsInstanceOf(context, JSNullMake(), arrayConstructor));
547
548 JSInternalStringRef functionBuf;
549
550 exception = NULL;
551 functionBuf = JSInternalStringCreateUTF8("rreturn Array;");
552 JSInternalStringRef lineBuf = JSInternalStringCreateUTF8("line");
553 assert(!JSFunctionMakeWithBody(context, functionBuf, NULL, 1, &exception));
554 assert(JSValueIsObject(exception));
555 v = JSObjectGetProperty(context, JSValueToObject(context, exception), lineBuf);
556 assert(v);
557 assertEqualsAsNumber(v, 2); // FIXME: Lexer::setCode bumps startingLineNumber by 1 -- we need to change internal callers so that it doesn't have to (saying '0' to mean '1' in the API would be really confusing -- it's really confusing internally, in fact)
558 JSInternalStringRelease(functionBuf);
559 JSInternalStringRelease(lineBuf);
560
561 functionBuf = JSInternalStringCreateUTF8("return Array;");
562 JSObjectRef function = JSFunctionMakeWithBody(context, functionBuf, NULL, 1, NULL);
563 JSInternalStringRelease(functionBuf);
564
565 assert(JSObjectIsFunction(function));
566 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
567 assert(JSValueIsEqual(context, v, arrayConstructor));
568
569 JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL);
570 assert(didInitialize);
571 JSInternalStringRef myObjectBuf = JSInternalStringCreateUTF8("MyObject");
572 JSObjectSetProperty(context, globalObject, myObjectBuf, myObject, kJSPropertyAttributeNone);
573 JSInternalStringRelease(myObjectBuf);
574
575 JSInternalStringRef printBuf = JSInternalStringCreateUTF8("print");
576 JSObjectRef printFunction = JSFunctionMake(context, print_callAsFunction);
577 JSObjectSetProperty(context, globalObject, printBuf, printFunction, kJSPropertyAttributeNone);
578 JSInternalStringRelease(printBuf);
579
580 assert(JSObjectSetPrivate(printFunction, (void*)1));
581 assert(JSObjectGetPrivate(printFunction) == (void*)1);
582
583 JSInternalStringRef myConstructorBuf = JSInternalStringCreateUTF8("MyConstructor");
584 JSObjectRef myConstructor = JSConstructorMake(context, myConstructor_callAsConstructor);
585 JSObjectSetProperty(context, globalObject, myConstructorBuf, myConstructor, kJSPropertyAttributeNone);
586 JSInternalStringRelease(myConstructorBuf);
587
588 assert(JSObjectSetPrivate(myConstructor, (void*)1));
589 assert(JSObjectGetPrivate(myConstructor) == (void*)1);
590
591 o = JSObjectMake(context, NULL, NULL);
592 JSObjectSetProperty(context, o, jsOneStringBuf, JSNumberMake(1), kJSPropertyAttributeNone);
593 JSObjectSetProperty(context, o, jsCFStringBuf, JSNumberMake(1), kJSPropertyAttributeDontEnum);
594 JSPropertyEnumeratorRef enumerator = JSObjectCreatePropertyEnumerator(context, o);
595 int count = 0;
596 while (JSPropertyEnumeratorGetNext(enumerator))
597 ++count;
598 JSPropertyEnumeratorRelease(enumerator);
599 assert(count == 1); // jsCFString should not be enumerated
600
601 JSClassRef nullCallbacksClass = JSClassCreate(NULL, NULL, NULL, NULL);
602 JSClassRelease(nullCallbacksClass);
603
604 functionBuf = JSInternalStringCreateUTF8("return this;");
605 function = JSFunctionMakeWithBody(context, functionBuf, NULL, 1, NULL);
606 JSInternalStringRelease(functionBuf);
607 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL);
608 assert(JSValueIsEqual(context, v, globalObject));
609 v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL);
610 assert(JSValueIsEqual(context, v, o));
611
612 char* script = createStringWithContentsOfFile("testapi.js");
613 JSInternalStringRef scriptBuf = JSInternalStringCreateUTF8(script);
614 result = JSEvaluate(context, scriptBuf, NULL, NULL, 1, &exception);
615 if (JSValueIsUndefined(result))
616 printf("PASS: Test script executed successfully.\n");
617 else {
618 printf("FAIL: Test script returned unexcpected value:\n");
619 JSInternalStringRef exceptionBuf = JSValueCopyStringValue(context, exception);
620 CFStringRef exceptionCF = CFStringCreateWithJSInternalString(kCFAllocatorDefault, exceptionBuf);
621 CFShow(exceptionCF);
622 CFRelease(exceptionCF);
623 JSInternalStringRelease(exceptionBuf);
624 }
625 JSInternalStringRelease(scriptBuf);
626 free(script);
627
628 // Allocate a few dummies so that at least one will be collected
629 JSObjectMake(context, MyObject_class(context), 0);
630 JSObjectMake(context, MyObject_class(context), 0);
631 JSGCCollect();
632 assert(didFinalize);
633
634 JSContextDestroy(context);
635 printf("PASS: Program exited normally.\n");
636 return 0;
637}
638
639static char* createStringWithContentsOfFile(const char* fileName)
640{
641 char* buffer;
642
643 int buffer_size = 0;
644 int buffer_capacity = 1024;
645 buffer = (char*)malloc(buffer_capacity);
646
647 FILE* f = fopen(fileName, "r");
648 if (!f) {
649 fprintf(stderr, "Could not open file: %s\n", fileName);
650 return 0;
651 }
652
653 while (!feof(f) && !ferror(f)) {
654 buffer_size += fread(buffer + buffer_size, 1, buffer_capacity - buffer_size, f);
655 if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0'
656 buffer_capacity *= 2;
657 buffer = (char*)realloc(buffer, buffer_capacity);
658 assert(buffer);
659 }
660
661 assert(buffer_size < buffer_capacity);
662 }
663 fclose(f);
664 buffer[buffer_size] = '\0';
665
666 return buffer;
667}
Note: See TracBrowser for help on using the repository browser.