summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPeter Varga <pvarga@inf.u-szeged.hu>2012-04-12 15:08:28 +0200
committerQt by Nokia <qt-info@nokia.com>2012-05-08 12:37:10 +0200
commit22a37f2be87584db0c138a6e2a7f75b6b5666fd8 (patch)
tree80b2f4d4c4f8080bd5689358771fecf98d62adb8 /tests
parent03f18ba953fc042e12858335ebe660055623dd30 (diff)
downloadqtjsbackend-22a37f2be87584db0c138a6e2a7f75b6b5666fd8.tar.gz
Add testcases for fallback interceptors
Change-Id: I85d31c5443cbfca7462aa671d59a50f22fead9c4 Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/v8/tst_v8.cpp18
-rw-r--r--tests/auto/v8/v8main.cpp3
-rw-r--r--tests/auto/v8/v8test.cpp514
-rw-r--r--tests/auto/v8/v8test.h3
4 files changed, 536 insertions, 2 deletions
diff --git a/tests/auto/v8/tst_v8.cpp b/tests/auto/v8/tst_v8.cpp
index 005951e..d73bf91 100644
--- a/tests/auto/v8/tst_v8.cpp
+++ b/tests/auto/v8/tst_v8.cpp
@@ -63,6 +63,9 @@ private slots:
void typeOf();
void referenceerror();
void qtbug_24871();
+ void fallbackpropertyhandler_callbacks();
+ void fallbackpropertyhandler_in_prototype();
+ void fallbackpropertyhandler_nonempty();
};
void tst_v8::eval()
@@ -110,6 +113,21 @@ void tst_v8::qtbug_24871()
QVERIFY(v8test_qtbug_24871());
}
+void tst_v8::fallbackpropertyhandler_callbacks()
+{
+ QVERIFY(v8test_fallbackpropertyhandler_callbacks());
+}
+
+void tst_v8::fallbackpropertyhandler_in_prototype()
+{
+ QVERIFY(v8test_fallbackpropertyhandler_in_prototype());
+}
+
+void tst_v8::fallbackpropertyhandler_nonempty()
+{
+ QVERIFY(v8test_fallbackpropertyhandler_nonempty());
+}
+
int main(int argc, char *argv[])
{
V8::SetFlagsFromCommandLine(&argc, argv, true);
diff --git a/tests/auto/v8/v8main.cpp b/tests/auto/v8/v8main.cpp
index 95f8d73..2b48f3b 100644
--- a/tests/auto/v8/v8main.cpp
+++ b/tests/auto/v8/v8main.cpp
@@ -64,6 +64,9 @@ int main(int argc, char *argv[])
RUN_TEST(getcallingqmlglobal);
RUN_TEST(typeof);
RUN_TEST(referenceerror);
+ RUN_TEST(fallbackpropertyhandler_callbacks);
+ RUN_TEST(fallbackpropertyhandler_in_prototype);
+ RUN_TEST(fallbackpropertyhandler_nonempty);
return -1;
}
diff --git a/tests/auto/v8/v8test.cpp b/tests/auto/v8/v8test.cpp
index 3ea313f..afd1f9a 100644
--- a/tests/auto/v8/v8test.cpp
+++ b/tests/auto/v8/v8test.cpp
@@ -54,6 +54,11 @@ using namespace v8;
} \
}
+static inline Local<Value> CompileRun(const char* source)
+{
+ return Script::Compile(String::New(source))->Run();
+}
+
struct MyStringResource : public String::ExternalAsciiStringResource
{
static bool wasDestroyed;
@@ -432,6 +437,9 @@ cleanup:
ENDTEST();
}
+#undef VARNAME
+#undef VARVALUE
+
bool v8test_typeof()
{
BEGINTEST();
@@ -529,5 +537,507 @@ cleanup:
ENDTEST();
}
-#undef VARNAME
-#undef VARVALUE
+#define DATA "fallbackpropertyhandler callbacks test"
+
+namespace CallbackType {
+ enum {
+ Error,
+ Getter,
+ Setter,
+ Query,
+ Deleter,
+ Enumerator
+ };
+}
+
+bool checkInterceptorCalled(Local<Object> obj, int index)
+{
+ if (obj->GetInternalField(index)->IsTrue()) {
+ obj->SetInternalField(index, False());
+ return true;
+ }
+
+ return false;
+}
+
+Handle<Value> EmptyInterceptorGetter(Local<String> name,
+ const AccessorInfo& info)
+{
+ Local<Object> self = info.This();
+ Local<String> data = String::New(DATA);
+
+ if (name->IsUndefined()) {
+ self->SetInternalField(CallbackType::Error, True());
+ return Handle<Value>();
+ }
+
+ if (!data->Equals(info.Data())) {
+ self->SetInternalField(CallbackType::Error, True());
+ return Handle<Value>();
+ }
+
+ self->SetInternalField(CallbackType::Getter, True());
+ return Handle<Value>();
+}
+
+Handle<Value> EmptyInterceptorSetter(Local<String> name,
+ Local<Value> value,
+ const AccessorInfo& info)
+{
+ Local<Object> self = info.This();
+ Local<String> data = String::New(DATA);
+
+ if (name->IsUndefined() || value->IsUndefined()) {
+ self->SetInternalField(CallbackType::Error, True());
+ return Handle<Value>();
+ }
+
+ if (!data->Equals(info.Data())) {
+ self->SetInternalField(CallbackType::Error, True());
+ return Handle<Value>();
+ }
+
+ self->SetInternalField(CallbackType::Setter, True());
+ return Handle<Value>();
+}
+
+Handle<Integer> EmptyInterceptorQuery(Local<String> name,
+ const AccessorInfo& info)
+{
+ Local<Object> self = info.This();
+ Local<String> data = String::New(DATA);
+
+ if (name->IsUndefined()) {
+ self->SetInternalField(CallbackType::Error, True());
+ return Handle<Integer>();
+ }
+
+ if (!data->Equals(info.Data())) {
+ self->SetInternalField(CallbackType::Error, True());
+ return Handle<Integer>();
+ }
+
+ self->SetInternalField(CallbackType::Query, True());
+ return Handle<Integer>();
+}
+
+Handle<Boolean> EmptyInterceptorDeleter(Local<String> name,
+ const AccessorInfo& info)
+{
+ Local<Object> self = info.This();
+ Local<String> data = String::New(DATA);
+
+ if (name->IsUndefined()) {
+ self->SetInternalField(CallbackType::Error, True());
+ return Handle<Boolean>();
+ }
+
+ if (!data->Equals(info.Data())) {
+ self->SetInternalField(CallbackType::Error, True());
+ return Handle<Boolean>();
+ }
+
+ self->SetInternalField(CallbackType::Deleter, True());
+ return Handle<Boolean>();
+}
+
+Handle<Array> EmptyInterceptorEnumerator(const AccessorInfo& info)
+{
+ Local<Object> self = info.This();
+ Local<String> data = String::New(DATA);
+
+ if (!data->Equals(info.Data())) {
+ self->SetInternalField(CallbackType::Error, True());
+ return Handle<Array>();
+ }
+
+ self->SetInternalField(CallbackType::Enumerator, True());
+ return Handle<Array>();
+}
+
+// Check whether the callbacks of fallback-named-property interceptors
+// called adequately.
+bool v8test_fallbackpropertyhandler_callbacks()
+{
+ BEGINTEST();
+
+ HandleScope handle_scope;
+ Persistent<Context> context = Context::New();
+ Context::Scope context_scope(context);
+
+ Handle<ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetFallbackPropertyHandler(EmptyInterceptorGetter,
+ EmptyInterceptorSetter,
+ EmptyInterceptorQuery,
+ EmptyInterceptorDeleter,
+ EmptyInterceptorEnumerator,
+ String::New(DATA));
+ templ->SetInternalFieldCount(6);
+ Local<Object> obj = templ->NewInstance();
+ obj->SetInternalField(CallbackType::Error, False());
+ obj->SetInternalField(CallbackType::Getter, False());
+ obj->SetInternalField(CallbackType::Setter, False());
+ obj->SetInternalField(CallbackType::Query, False());
+ obj->SetInternalField(CallbackType::Deleter, False());
+ obj->SetInternalField(CallbackType::Enumerator, False());
+ Local<Value> result;
+
+ context->Global()->Set(String::New("obj"), obj);
+
+ // Check Getter/Setter callbacks
+ obj->Set(String::New("a"), Integer::New(28));
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Getter));
+ VERIFY(checkInterceptorCalled(obj, CallbackType::Setter));
+
+ result = obj->Get(String::New("a"));
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Getter));
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Setter));
+ VERIFY(28 == result->Int32Value());
+
+ obj->Set(String::New("a"), Integer::New(28));
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Getter));
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Setter));
+
+ result = obj->Get(String::New("b"));
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(checkInterceptorCalled(obj, CallbackType::Getter));
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Setter));
+ VERIFY(result->IsUndefined());
+
+ obj->ForceSet(String::New("b"), Integer::New(42));
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Getter));
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Setter));
+
+ result = obj->Get(String::New("b"));
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Getter));
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Setter));
+ VERIFY(42 == result->Int32Value());
+
+ result = CompileRun("obj.c = 47");
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Getter));
+ VERIFY(checkInterceptorCalled(obj, CallbackType::Setter));
+ VERIFY(47 == result->Int32Value());
+
+ result = CompileRun("obj.d");
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(checkInterceptorCalled(obj, CallbackType::Getter));
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Setter));
+ VERIFY(result->IsUndefined());
+
+ result = CompileRun("obj.a");
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Getter));
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Setter));
+ VERIFY(28 == result->Int32Value());
+
+ result = CompileRun("obj.b = 5");
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Getter));
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Setter));
+ VERIFY(5 == result->Int32Value());
+
+ // Check query callback
+ obj->HasOwnProperty(String::New("a"));
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Query));
+
+ result = CompileRun("'a' in obj");
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Query));
+
+ obj->HasOwnProperty(String::New("x"));
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(checkInterceptorCalled(obj, CallbackType::Query));
+
+ result = CompileRun("'x' in obj");
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(checkInterceptorCalled(obj, CallbackType::Query));
+
+ // Check deleter callback
+ obj->Delete(String::New("a"));
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Deleter));
+
+ result = CompileRun("delete obj.b");
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(!checkInterceptorCalled(obj, CallbackType::Deleter));
+
+ obj->Delete(String::New("x"));
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(checkInterceptorCalled(obj, CallbackType::Deleter));
+
+ result = CompileRun("delete obj.x");
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(checkInterceptorCalled(obj, CallbackType::Deleter));
+
+ // Check enumerator callback
+ result = CompileRun("for (var p in obj) ;");
+ VERIFY(obj->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(checkInterceptorCalled(obj, CallbackType::Enumerator));
+
+cleanup:
+ context.Dispose();
+
+ ENDTEST();
+}
+
+#undef DATA
+
+Handle<Object> bottom;
+Handle<Object> middle;
+Handle<Object> top;
+
+Handle<Value> CheckThisFallbackPropertyHandler(Local<String> name,
+ const AccessorInfo& info)
+{
+ Local<Object> self = info.This();
+ Local<Object> holder = info.Holder();
+
+ if (name->IsUndefined()) {
+ self->SetInternalField(CallbackType::Error, True());
+ return Handle<Value>();
+ }
+
+ bool check = self->Equals(bottom);
+ bottom->SetInternalField(CallbackType::Error, Boolean::New(!check));
+
+ if (holder->Equals(bottom)) {
+ bottom->SetInternalField(1, String::New("bottom"));
+ } else if (holder->Equals(middle)) {
+ bottom->SetInternalField(1, String::New("middle"));
+ } else if (holder->Equals(top)) {
+ bottom->SetInternalField(1, String::New("top"));
+ } else {
+ bottom->SetInternalField(1, String::New(""));
+ }
+
+ return Handle<Value>();
+}
+
+Handle<Value> CheckThisFallbackPropertySetter(Local<String> name,
+ Local<Value> value,
+ const AccessorInfo& info)
+{
+ Local<Object> self = info.This();
+ Local<Object> holder = info.Holder();
+
+ if (name->IsUndefined() || value->IsUndefined()) {
+ self->SetInternalField(CallbackType::Error, True());
+ return Handle<Value>();
+ }
+
+ bool check = self->Equals(bottom);
+ bottom->SetInternalField(CallbackType::Error, Boolean::New(!check));
+
+ if (holder->Equals(bottom)) {
+ bottom->SetInternalField(1, String::New("bottom"));
+ } else if (holder->Equals(middle)) {
+ bottom->SetInternalField(1, String::New("middle"));
+ } else if (holder->Equals(top)) {
+ bottom->SetInternalField(1, String::New("top"));
+ } else {
+ bottom->SetInternalField(1, String::New(""));
+ }
+
+ return Handle<Value>();
+}
+
+Handle<Integer> CheckThisFallbackPropertyQuery(Local<String> name,
+ const AccessorInfo& info)
+{
+ Local<Object> self = info.This();
+
+ if (name->IsUndefined()) {
+ self->SetInternalField(CallbackType::Error, True());
+ return Handle<Integer>();
+ }
+
+ bool check = self->Equals(bottom);
+ bottom->SetInternalField(CallbackType::Error, Boolean::New(!check));
+
+ return Handle<Integer>();
+}
+
+Handle<Boolean> CheckThisFallbackPropertyDeleter(Local<String> name,
+ const AccessorInfo& info)
+{
+ Local<Object> self = info.This();
+
+ if (name->IsUndefined()) {
+ self->SetInternalField(CallbackType::Error, True());
+ return Handle<Boolean>();
+ }
+
+ bool check = self->Equals(bottom);
+ bottom->SetInternalField(CallbackType::Error, Boolean::New(!check));
+
+ return Handle<Boolean>();
+}
+
+Handle<Array> CheckThisFallbackPropertyEnumerator(const AccessorInfo& info)
+{
+ bool check = info.This()->Equals(bottom);
+ // Use field index 1 here due to query fallback interceptor can be called
+ // by enumerator
+ bottom->SetInternalField(1, Boolean::New(!check));
+
+ return Handle<Array>();
+}
+
+bool v8test_fallbackpropertyhandler_in_prototype()
+{
+ BEGINTEST();
+
+ HandleScope handle_scope;
+ Persistent<Context> context = Context::New();
+ Context::Scope context_scope(context);
+
+ Local<String> bottom_name = String::New("bottom");
+ Local<String> middle_name = String::New("middle");
+ Local<String> top_name = String::New("top");
+
+ // Set up a prototype chain with three interceptors.
+ Handle<FunctionTemplate> templ = FunctionTemplate::New();
+ templ->InstanceTemplate()->SetInternalFieldCount(2);
+ templ->InstanceTemplate()->SetNamedPropertyHandler(
+ CheckThisFallbackPropertyHandler,
+ CheckThisFallbackPropertySetter,
+ CheckThisFallbackPropertyQuery,
+ CheckThisFallbackPropertyDeleter,
+ CheckThisFallbackPropertyEnumerator);
+
+ bottom = templ->GetFunction()->NewInstance();
+ top = templ->GetFunction()->NewInstance();
+ middle = templ->GetFunction()->NewInstance();
+
+ bottom->Set(bottom_name, Integer::New(0));
+ middle->Set(middle_name, Integer::New(0));
+ top->Set(top_name, Integer::New(0));
+
+ bottom->Set(String::New("__proto__"), middle);
+ middle->Set(String::New("__proto__"), top);
+ context->Global()->Set(String::New("obj"), bottom);
+
+ // Set Error field to true in every case to check whether the interceptor is called.
+ bottom->SetInternalField(CallbackType::Error, True());
+ CompileRun("obj.x");
+ VERIFY(bottom->GetInternalField(CallbackType::Error)->IsFalse());
+
+ bottom->SetInternalField(CallbackType::Error, True());
+ CompileRun("obj.y = 42");
+ VERIFY(bottom->GetInternalField(CallbackType::Error)->IsFalse());
+
+ bottom->SetInternalField(CallbackType::Error, True());
+ CompileRun("'x' in obj");
+ VERIFY(bottom->GetInternalField(CallbackType::Error)->IsFalse());
+
+ bottom->SetInternalField(CallbackType::Error, True());
+ CompileRun("delete obj.x");
+ VERIFY(bottom->GetInternalField(CallbackType::Error)->IsFalse());
+
+ bottom->SetInternalField(1, True());
+ CompileRun("for (var p in obj) ;");
+ // Check field index 1 here due to query fallback interceptor can be called
+ // by enumerator
+ VERIFY(bottom->GetInternalField(1)->IsFalse());
+
+ bottom->SetInternalField(1, String::New(""));
+ bottom->SetInternalField(CallbackType::Error, True());
+ CompileRun("obj.bottom");
+ VERIFY(bottom->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(bottom->GetInternalField(1)->ToString()->Equals(bottom_name));
+
+ bottom->SetInternalField(CallbackType::Error, True());
+ CompileRun("obj.middle");
+ VERIFY(bottom->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(bottom->GetInternalField(1)->ToString()->Equals(middle_name));
+
+ bottom->SetInternalField(CallbackType::Error, True());
+ CompileRun("obj.top");
+ VERIFY(bottom->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(bottom->GetInternalField(1)->ToString()->Equals(top_name));
+
+ bottom->SetInternalField(1, String::New(""));
+ bottom->SetInternalField(CallbackType::Error, True());
+ CompileRun("obj.bottom = 1");
+ VERIFY(bottom->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(bottom->GetInternalField(1)->ToString()->Equals(bottom_name));
+
+ bottom->SetInternalField(CallbackType::Error, True());
+ CompileRun("obj.cica = 1");
+ VERIFY(bottom->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(bottom->GetInternalField(1)->ToString()->Equals(bottom_name));
+
+ bottom->SetInternalField(CallbackType::Error, True());
+ CompileRun("obj.top = 1");
+ VERIFY(bottom->GetInternalField(CallbackType::Error)->IsFalse());
+ VERIFY(bottom->GetInternalField(1)->ToString()->Equals(bottom_name));
+
+cleanup:
+ context.Dispose();
+
+ ENDTEST();
+}
+
+Handle<Value> NonEmptyInterceptorGetter(Local<String> name,
+ const AccessorInfo& info)
+{
+ (void)info;
+
+ return name;
+}
+
+Handle<Value> NonEmptyInterceptorSetter(Local<String> name,
+ Local<Value> value,
+ const AccessorInfo& info)
+{
+ Local<Object> self = info.This();
+ self->ForceSet(name, String::Concat(name, value->ToString()));
+
+ return value;
+}
+
+bool v8test_fallbackpropertyhandler_nonempty()
+{
+ BEGINTEST();
+
+ HandleScope handle_scope;
+ Persistent<Context> context = Context::New();
+ Context::Scope context_scope(context);
+
+ Handle<ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetFallbackPropertyHandler(NonEmptyInterceptorGetter,
+ NonEmptyInterceptorSetter);
+ Local<Object> obj = templ->NewInstance();
+ Local<Value> result;
+
+ context->Global()->Set(String::New("obj"), obj);
+
+ result = obj->Get(String::New("a"));
+ VERIFY(result->IsString());
+ VERIFY(result->ToString()->Equals(String::New("a")));
+ result = CompileRun("obj.a");
+ VERIFY(result->IsString());
+ VERIFY(result->ToString()->Equals(String::New("a")));
+
+ obj->Set(String::New("a"), Integer::New(28));
+ result = obj->Get(String::New("a"));
+ VERIFY(result->IsString());
+ VERIFY(result->ToString()->Equals(String::New("a28")));
+
+ obj->Set(String::New("a"), Integer::New(42));
+ result = obj->Get(String::New("a"));
+ VERIFY(result->IsNumber());
+ VERIFY(42 == result->Int32Value());
+
+cleanup:
+ context.Dispose();
+
+ ENDTEST();
+}
diff --git a/tests/auto/v8/v8test.h b/tests/auto/v8/v8test.h
index d497384..9f91f8a 100644
--- a/tests/auto/v8/v8test.h
+++ b/tests/auto/v8/v8test.h
@@ -57,6 +57,9 @@ bool v8test_getcallingqmlglobal();
bool v8test_typeof();
bool v8test_referenceerror();
bool v8test_qtbug_24871();
+bool v8test_fallbackpropertyhandler_callbacks();
+bool v8test_fallbackpropertyhandler_in_prototype();
+bool v8test_fallbackpropertyhandler_nonempty();
#endif // V8TEST_H