diff options
author | Peter Varga <pvarga@inf.u-szeged.hu> | 2012-04-12 15:08:28 +0200 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-05-08 12:37:10 +0200 |
commit | 22a37f2be87584db0c138a6e2a7f75b6b5666fd8 (patch) | |
tree | 80b2f4d4c4f8080bd5689358771fecf98d62adb8 /tests | |
parent | 03f18ba953fc042e12858335ebe660055623dd30 (diff) | |
download | qtjsbackend-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.cpp | 18 | ||||
-rw-r--r-- | tests/auto/v8/v8main.cpp | 3 | ||||
-rw-r--r-- | tests/auto/v8/v8test.cpp | 514 | ||||
-rw-r--r-- | tests/auto/v8/v8test.h | 3 |
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 |