📄 test-api.cc
字号:
// Copyright 2007-2008 the V8 project authors. All rights reserved.// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following// disclaimer in the documentation and/or other materials provided// with the distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived// from this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.#include <map>#include <string>#include "v8.h"#include "api.h"#include "snapshot.h"#include "platform.h"#include "top.h"#include "cctest.h"static bool IsNaN(double x) {#ifdef WIN32 return _isnan(x);#else return isnan(x);#endif}using ::v8::ObjectTemplate;using ::v8::Value;using ::v8::Context;using ::v8::Local;using ::v8::String;using ::v8::Script;using ::v8::Function;using ::v8::AccessorInfo;using ::v8::Extension;namespace i = ::v8::internal;static Local<Value> v8_num(double x) { return v8::Number::New(x);}static Local<String> v8_str(const char* x) { return String::New(x);}static Local<Script> v8_compile(const char* x) { return Script::Compile(v8_str(x));}// A LocalContext holds a reference to a v8::Context.class LocalContext { public: LocalContext(v8::ExtensionConfiguration* extensions = 0, v8::Handle<ObjectTemplate> global_template = v8::Handle<ObjectTemplate>(), v8::Handle<Value> global_object = v8::Handle<Value>()) : context_(Context::New(extensions, global_template, global_object)) { context_->Enter(); } virtual ~LocalContext() { context_->Exit(); context_.Dispose(); } Context* operator->() { return *context_; } Context* operator*() { return *context_; } Local<Context> local() { return Local<Context>::New(context_); } bool IsReady() { return !context_.IsEmpty(); } private: v8::Persistent<Context> context_;};// Switches between all the Api tests using the threading support.// In order to get a surprising but repeatable pattern of thread// switching it has extra semaphores to control the order in which// the tests alternate, not relying solely on the big V8 lock.//// A test is augmented with calls to ApiTestFuzzer::Fuzz() in its// callbacks. This will have no effect when we are not running the// thread fuzzing test. In the thread fuzzing test it will// pseudorandomly select a successor thread and switch execution// to that thread, suspending the current test.class ApiTestFuzzer: public v8::internal::Thread { public: void CallTest(); explicit ApiTestFuzzer(int num) : test_number_(num), gate_(v8::internal::OS::CreateSemaphore(0)), active_(true) { } // The ApiTestFuzzer is also a Thread, so it has a Run method. virtual void Run(); enum PartOfTest { FIRST_PART, SECOND_PART }; static void Setup(PartOfTest part); static void RunAllTests(); static void TearDown(); // This method switches threads if we are running the Threading test. // Otherwise it does nothing. static void Fuzz(); private: static bool fuzzing_; static int tests_being_run_; static int current_; static int active_tests_; static bool NextThread(); int test_number_; v8::internal::Semaphore* gate_; bool active_; void ContextSwitch(); static int GetNextTestNumber(); static v8::internal::Semaphore* all_tests_done_;};#define THREADED_TEST(Name) \ static void Test##Name(); \ RegisterThreadedTest register_##Name(Test##Name); \ /* */ TEST(Name)class RegisterThreadedTest { public: explicit RegisterThreadedTest(CcTest::TestFunction* callback) : callback_(callback) { prev_ = first_; first_ = this; count_++; } static int count() { return count_; } static RegisterThreadedTest* nth(int i) { ASSERT(i < count()); RegisterThreadedTest* current = first_; while (i > 0) { i--; current = current->prev_; } return current; } CcTest::TestFunction* callback() { return callback_; } ApiTestFuzzer* fuzzer_; private: static RegisterThreadedTest* first_; static int count_; CcTest::TestFunction* callback_; RegisterThreadedTest* prev_;};RegisterThreadedTest *RegisterThreadedTest::first_ = NULL;int RegisterThreadedTest::count_ = 0;static int signature_callback_count;static v8::Handle<Value> IncrementingSignatureCallback( const v8::Arguments& args) { ApiTestFuzzer::Fuzz(); signature_callback_count++; v8::Handle<v8::Array> result = v8::Array::New(args.Length()); for (int i = 0; i < args.Length(); i++) result->Set(v8::Integer::New(i), args[i]); return result;}static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) { ApiTestFuzzer::Fuzz(); v8::Handle<v8::Array> result = v8::Array::New(args.Length()); for (int i = 0; i < args.Length(); i++) { result->Set(v8::Integer::New(i), args[i]); } return result;}THREADED_TEST(Handles) { v8::HandleScope scope; Local<Context> local_env; { LocalContext env; local_env = env.local(); } // Local context should still be live. CHECK(!local_env.IsEmpty()); local_env->Enter(); v8::Handle<v8::Primitive> undef = v8::Undefined(); CHECK(!undef.IsEmpty()); CHECK(undef->IsUndefined()); const char* c_source = "1 + 2 + 3"; Local<String> source = String::New(c_source); Local<Script> script = Script::Compile(source); CHECK_EQ(6, script->Run()->Int32Value()); local_env->Exit();}// Helper function that compiles and runs the source.static Local<Value> CompileRun(const char* source) { return Script::Compile(String::New(source))->Run();}THREADED_TEST(ReceiverSignature) { v8::HandleScope scope; LocalContext env; v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(); v8::Handle<v8::Signature> sig = v8::Signature::New(fun); fun->PrototypeTemplate()->Set( v8_str("m"), v8::FunctionTemplate::New(IncrementingSignatureCallback, v8::Handle<Value>(), sig)); env->Global()->Set(v8_str("Fun"), fun->GetFunction()); signature_callback_count = 0; CompileRun( "var o = new Fun();" "o.m();"); CHECK_EQ(1, signature_callback_count); v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(); sub_fun->Inherit(fun); env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction()); CompileRun( "var o = new SubFun();" "o.m();"); CHECK_EQ(2, signature_callback_count); v8::TryCatch try_catch; CompileRun( "var o = { };" "o.m = Fun.prototype.m;" "o.m();"); CHECK_EQ(2, signature_callback_count); CHECK(try_catch.HasCaught()); try_catch.Reset(); v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New(); sub_fun->Inherit(fun); env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction()); CompileRun( "var o = new UnrelFun();" "o.m = Fun.prototype.m;" "o.m();"); CHECK_EQ(2, signature_callback_count); CHECK(try_catch.HasCaught());}THREADED_TEST(ArgumentSignature) { v8::HandleScope scope; LocalContext env; v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(); cons->SetClassName(v8_str("Cons")); v8::Handle<v8::Signature> sig = v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons); v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig); env->Global()->Set(v8_str("Cons"), cons->GetFunction()); env->Global()->Set(v8_str("Fun1"), fun->GetFunction()); v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';"); ASSERT(value1->IsTrue()); v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';"); ASSERT(value2->IsTrue()); v8::Handle<Value> value3 = CompileRun("Fun1() == '';"); ASSERT(value3->IsTrue()); v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(); cons1->SetClassName(v8_str("Cons1")); v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(); cons2->SetClassName(v8_str("Cons2")); v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(); cons3->SetClassName(v8_str("Cons3")); v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 }; v8::Handle<v8::Signature> wsig = v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args); v8::Handle<v8::FunctionTemplate> fun2 = v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig); env->Global()->Set(v8_str("Cons1"), cons1->GetFunction()); env->Global()->Set(v8_str("Cons2"), cons2->GetFunction()); env->Global()->Set(v8_str("Cons3"), cons3->GetFunction()); env->Global()->Set(v8_str("Fun2"), fun2->GetFunction()); v8::Handle<Value> value4 = CompileRun( "Fun2(new Cons1(), new Cons2(), new Cons3()) ==" "'[object Cons1],[object Cons2],[object Cons3]'"); ASSERT(value4->IsTrue()); v8::Handle<Value> value5 = CompileRun( "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'"); ASSERT(value5->IsTrue()); v8::Handle<Value> value6 = CompileRun( "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'"); ASSERT(value6->IsTrue()); v8::Handle<Value> value7 = CompileRun( "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == " "'[object Cons1],[object Cons2],[object Cons3],d';"); ASSERT(value7->IsTrue()); v8::Handle<Value> value8 = CompileRun( "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'"); ASSERT(value8->IsTrue());}THREADED_TEST(HulIgennem) { v8::HandleScope scope; LocalContext env; v8::Handle<v8::Primitive> undef = v8::Undefined(); Local<String> undef_str = undef->ToString(); char* value = i::NewArray<char>(undef_str->Length() + 1); undef_str->WriteAscii(value); CHECK_EQ(0, strcmp(value, "undefined")); i::DeleteArray(value);}THREADED_TEST(Access) { v8::HandleScope scope; LocalContext env; Local<v8::Object> obj = v8::Object::New(); Local<Value> foo_before = obj->Get(v8_str("foo")); CHECK(foo_before->IsUndefined()); Local<String> bar_str = v8_str("bar"); obj->Set(v8_str("foo"), bar_str); Local<Value> foo_after = obj->Get(v8_str("foo")); CHECK(!foo_after->IsUndefined()); CHECK(foo_after->IsString()); CHECK_EQ(bar_str, foo_after);}THREADED_TEST(Script) { v8::HandleScope scope; LocalContext env; const char* c_source = "1 + 2 + 3"; Local<String> source = String::New(c_source); Local<Script> script = Script::Compile(source); CHECK_EQ(6, script->Run()->Int32Value());}static uint16_t* AsciiToTwoByteString(const char* source) { size_t array_length = strlen(source) + 1; uint16_t* converted = i::NewArray<uint16_t>(array_length); for (size_t i = 0; i < array_length; i++) converted[i] = source[i]; return converted;}class TestResource: public String::ExternalStringResource { public: static int dispose_count; explicit TestResource(uint16_t* data) : data_(data), length_(0) { while (data[length_]) ++length_; } ~TestResource() { i::DeleteArray(data_); ++dispose_count; } const uint16_t* data() const { return data_; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -