From 1442c1c6de1009a7f451a443c02b1450bcb5bc44 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Sat, 18 Jan 2014 22:49:18 +0000 Subject: addons: build and test examples fix #6910 --- .gitignore | 1 + Makefile | 29 ++- doc/api/addons.markdown | 197 +++++++++++---------- test/addons/async-hello-world/binding.cc | 25 +-- test/addons/at-exit/binding.cc | 3 +- test/addons/hello-world-function-export/binding.cc | 7 +- test/addons/hello-world/binding.cc | 7 +- test/addons/testcfg.py | 6 + test/testpy/__init__.py | 25 +++ tools/doc/addon-verify.js | 94 ++++++++++ 10 files changed, 277 insertions(+), 117 deletions(-) create mode 100644 test/addons/testcfg.py create mode 100644 tools/doc/addon-verify.js diff --git a/.gitignore b/.gitignore index e0f5151c75e..a86377cbe44 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ ipch/ /dist-osx /npm.wxs /tools/msvs/npm.wixobj +/test/addons/doc-*/ email.md deps/v8-* ./node_modules diff --git a/Makefile b/Makefile index 0406b1d72f8..cb27a33104f 100644 --- a/Makefile +++ b/Makefile @@ -100,26 +100,38 @@ test/gc/node_modules/weak/build/Release/weakref.node: --directory="$(shell pwd)/test/gc/node_modules/weak" \ --nodedir="$(shell pwd)" +build-addons: + @if [ ! -f node ]; then make all; fi + rm -rf test/addons/doc-*/ + ./node tools/doc/addon-verify.js + $(foreach dir, \ + $(sort $(dir $(wildcard test/addons/*/*.gyp))), \ + ./node deps/npm/node_modules/node-gyp/bin/node-gyp rebuild \ + --directory="$(shell pwd)/$(dir)" \ + --nodedir="$(shell pwd)" && ) echo "build done" + test-gc: all test/gc/node_modules/weak/build/Release/weakref.node $(PYTHON) tools/test.py --mode=release gc -test-all: all test/gc/node_modules/weak/build/Release/weakref.node +test-build: all build-addons + +test-all: test-build test/gc/node_modules/weak/build/Release/weakref.node $(PYTHON) tools/test.py --mode=debug,release make test-npm -test-all-http1: all +test-all-http1: test-build $(PYTHON) tools/test.py --mode=debug,release --use-http1 -test-all-valgrind: all +test-all-valgrind: test-build $(PYTHON) tools/test.py --mode=debug,release --valgrind -test-release: all +test-release: test-build $(PYTHON) tools/test.py --mode=release -test-debug: all +test-debug: test-build $(PYTHON) tools/test.py --mode=debug -test-message: all +test-message: test-build $(PYTHON) tools/test.py message test-simple: all @@ -140,6 +152,9 @@ test-npm: node test-npm-publish: node npm_package_config_publishtest=true ./node deps/npm/test/run.js +test-addons: test-build + $(PYTHON) tools/test.py --mode=release addons + apidoc_sources = $(wildcard doc/api/*.markdown) apidocs = $(addprefix out/,$(apidoc_sources:.markdown=.html)) \ $(addprefix out/,$(apidoc_sources:.markdown=.json)) @@ -418,4 +433,4 @@ cpplint: lint: jslint cpplint -.PHONY: lint cpplint jslint bench clean docopen docclean doc dist distclean check uninstall install install-includes install-bin all staticlib dynamiclib test test-all website-upload pkg blog blogclean tar binary release-only bench-http-simple bench-idle bench-all bench bench-misc bench-array bench-buffer bench-net bench-http bench-fs bench-tls +.PHONY: lint cpplint jslint bench clean docopen docclean doc dist distclean check uninstall install install-includes install-bin all staticlib dynamiclib test test-all test-addons build-addons website-upload pkg blog blogclean tar binary release-only bench-http-simple bench-idle bench-all bench bench-misc bench-array bench-buffer bench-net bench-http bench-fs bench-tls diff --git a/doc/api/addons.markdown b/doc/api/addons.markdown index ff97326533f..b6f3fd45c01 100644 --- a/doc/api/addons.markdown +++ b/doc/api/addons.markdown @@ -38,22 +38,22 @@ the following JavaScript code: First we create a file `hello.cc`: + // hello.cc #include using namespace v8; - Handle Method(const Arguments& args) { + void Method(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); - return scope.Close(String::New("world")); + args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world")); } void init(Handle exports) { - exports->Set(String::NewSymbol("hello"), - FunctionTemplate::New(Method)->GetFunction()); + NODE_SET_METHOD(exports, "hello", Method); } - NODE_MODULE(hello, init) + NODE_MODULE(addon, init) Note that all Node addons must export an initialization function: @@ -66,7 +66,7 @@ There is no semi-colon after `NODE_MODULE` as it's not a function (see The `module_name` needs to match the filename of the final binary (minus the .node suffix). -The source code needs to be built into `hello.node`, the binary Addon. To +The source code needs to be built into `addon.node`, the binary Addon. To do this we create a file called `binding.gyp` which describes the configuration to build your module in a JSON-like format. This file gets compiled by [node-gyp](https://github.com/TooTallNate/node-gyp). @@ -74,7 +74,7 @@ to build your module in a JSON-like format. This file gets compiled by { "targets": [ { - "target_name": "hello", + "target_name": "addon", "sources": [ "hello.cc" ] } ] @@ -93,7 +93,8 @@ in `build/Release/`. You can now use the binary addon in a Node project `hello.js` by pointing `require` to the recently built `hello.node` module: - var addon = require('./build/Release/hello'); + // hello.js + var addon = require('./build/Release/addon'); console.log(addon.hello()); // 'world' @@ -138,39 +139,42 @@ The following pattern illustrates how to read arguments from JavaScript function calls and return a result. This is the main and only needed source `addon.cc`: + // addon.cc #include using namespace v8; - Handle Add(const Arguments& args) { + void Add(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); if (args.Length() < 2) { - ThrowException(Exception::TypeError( - String::New("Wrong number of arguments"))); - return scope.Close(Undefined(isolate)); + isolate->ThrowException(Exception::TypeError( + String::NewFromUtf8(isolate, "Wrong number of arguments"))); + return; } if (!args[0]->IsNumber() || !args[1]->IsNumber()) { - ThrowException(Exception::TypeError(String::New("Wrong arguments"))); - return scope.Close(Undefined(isolate)); + isolate->ThrowException(Exception::TypeError( + String::NewFromUtf8(isolate, "Wrong arguments"))); + return; } Local num = Number::New(args[0]->NumberValue() + args[1]->NumberValue()); - return scope.Close(num); + + args.GetReturnValue().Set(num); } void Init(Handle exports) { - exports->Set(String::NewSymbol("add"), - FunctionTemplate::New(Add)->GetFunction()); + NODE_SET_METHOD(exports, "add", Add); } NODE_MODULE(addon, Init) You can test it with the following JavaScript snippet: + // test.js var addon = require('./build/Release/addon'); console.log( 'This should be eight:', addon.add(3,5) ); @@ -181,25 +185,23 @@ You can test it with the following JavaScript snippet: You can pass JavaScript functions to a C++ function and execute them from there. Here's `addon.cc`: + // addon.cc #include using namespace v8; - Handle RunCallback(const Arguments& args) { + void RunCallback(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); Local cb = Local::Cast(args[0]); const unsigned argc = 1; - Local argv[argc] = { String::New("hello world") }; + Local argv[argc] = { String::NewFromUtf8(isolate, "hello world") }; cb->Call(Context::GetCurrent()->Global(), argc, argv); - - return scope.Close(Undefined(isolate)); } void Init(Handle exports, Handle module) { - module->Set(String::NewSymbol("exports"), - FunctionTemplate::New(RunCallback)->GetFunction()); + NODE_SET_METHOD(module, "exports", RunCallback); } NODE_MODULE(addon, Init) @@ -211,6 +213,7 @@ adding the function as a property of `exports`. To test it run the following JavaScript snippet: + // test.js var addon = require('./build/Release/addon'); addon(function(msg){ @@ -224,29 +227,30 @@ You can create and return new objects from within a C++ function with this `addon.cc` pattern, which returns an object with property `msg` that echoes the string passed to `createObject()`: + // addon.cc #include using namespace v8; - Handle CreateObject(const Arguments& args) { + void CreateObject(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); Local obj = Object::New(); - obj->Set(String::NewSymbol("msg"), args[0]->ToString()); + obj->Set(String::NewFromUtf8(isolate, "msg"), args[0]->ToString()); - return scope.Close(obj); + args.GetReturnValue().Set(obj); } void Init(Handle exports, Handle module) { - module->Set(String::NewSymbol("exports"), - FunctionTemplate::New(CreateObject)->GetFunction()); + NODE_SET_METHOD(module, "exports", CreateObject); } NODE_MODULE(addon, Init) To test it in JavaScript: + // test.js var addon = require('./build/Release/addon'); var obj1 = addon('hello'); @@ -259,17 +263,18 @@ To test it in JavaScript: This pattern illustrates how to create and return a JavaScript function that wraps a C++ function: + // addon.cc #include using namespace v8; - Handle MyFunction(const Arguments& args) { + void MyFunction(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); - return scope.Close(String::New("hello world")); + args.GetReturnValue().Set(String::NewFromUtf8(isolate, "hello world")); } - Handle CreateFunction(const Arguments& args) { + void CreateFunction(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); @@ -277,20 +282,20 @@ wraps a C++ function: Local fn = tpl->GetFunction(); // omit this to make it anonymous - fn->SetName(String::NewSymbol("theFunction")); + fn->SetName(String::NewFromUtf8(isolate, "theFunction")); - return scope.Close(fn); + args.GetReturnValue().Set(fn); } void Init(Handle exports, Handle module) { - module->Set(String::NewSymbol("exports"), - FunctionTemplate::New(CreateFunction)->GetFunction()); + NODE_SET_METHOD(module, "exports", CreateFunction); } NODE_MODULE(addon, Init) To test: + // test.js var addon = require('./build/Release/addon'); var fn = addon(); @@ -303,6 +308,7 @@ Here we will create a wrapper for a C++ object/class `MyObject` that can be instantiated in JavaScript through the `new` operator. First prepare the main module `addon.cc`: + // addon.cc #include #include "myobject.h" @@ -316,10 +322,12 @@ module `addon.cc`: Then in `myobject.h` make your wrapper inherit from `node::ObjectWrap`: + // myobject.h #ifndef MYOBJECT_H #define MYOBJECT_H #include + #include class MyObject : public node::ObjectWrap { public: @@ -329,8 +337,8 @@ Then in `myobject.h` make your wrapper inherit from `node::ObjectWrap`: explicit MyObject(double value = 0); ~MyObject(); - static v8::Handle New(const v8::Arguments& args); - static v8::Handle PlusOne(const v8::Arguments& args); + static void New(const v8::FunctionCallbackInfo& args); + static void PlusOne(const v8::FunctionCallbackInfo& args); static v8::Persistent constructor; double value_; }; @@ -341,8 +349,7 @@ And in `myobject.cc` implement the various methods that you want to expose. Here we expose the method `plusOne` by adding it to the constructor's prototype: - #include - #include + // myobject.cc #include "myobject.h" using namespace v8; @@ -360,20 +367,18 @@ prototype: // Prepare constructor template Local tpl = FunctionTemplate::New(New); - tpl->SetClassName(String::NewSymbol("MyObject")); + tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype - tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"), - FunctionTemplate::New(PlusOne)->GetFunction()); - - Persistent constructor - = Persistent::New(isolate, tpl->GetFunction()); + NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne); - exports->Set(String::NewSymbol("MyObject"), constructor); + constructor.Reset(isolate, tpl->GetFunction()); + exports->Set(String::NewFromUtf8(isolate, "MyObject"), + tpl->GetFunction()); } - Handle MyObject::New(const Arguments& args) { + void MyObject::New(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); @@ -382,27 +387,29 @@ prototype: double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); MyObject* obj = new MyObject(value); obj->Wrap(args.This()); - return args.This(); + args.GetReturnValue().Set(args.This()); } else { // Invoked as plain function `MyObject(...)`, turn into construct call. const int argc = 1; Local argv[argc] = { args[0] }; - return scope.Close(constructor->NewInstance(argc, argv)); + Local cons = Local::New(isolate, constructor); + args.GetReturnValue().Set(cons->NewInstance(argc, argv)); } } - Handle MyObject::PlusOne(const Arguments& args) { + void MyObject::PlusOne(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); MyObject* obj = ObjectWrap::Unwrap(args.This()); obj->value_ += 1; - return scope.Close(Number::New(obj->value_)); + args.GetReturnValue().Set(Number::New(obj->value_)); } Test it with: + // test.js var addon = require('./build/Release/addon'); var obj = new addon.MyObject(10); @@ -421,22 +428,22 @@ explicitly instantiating them with the `new` operator in JavaScript, e.g. Let's register our `createObject` method in `addon.cc`: + // addon.cc #include #include "myobject.h" using namespace v8; - Handle CreateObject(const Arguments& args) { + void CreateObject(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); - return scope.Close(MyObject::NewInstance(args)); + MyObject::NewInstance(args); } void InitAll(Handle exports, Handle module) { MyObject::Init(); - module->Set(String::NewSymbol("exports"), - FunctionTemplate::New(CreateObject)->GetFunction()); + NODE_SET_METHOD(module, "exports", CreateObject); } NODE_MODULE(addon, InitAll) @@ -444,22 +451,24 @@ Let's register our `createObject` method in `addon.cc`: In `myobject.h` we now introduce the static method `NewInstance` that takes care of instantiating the object (i.e. it does the job of `new` in JavaScript): + // myobject.h #ifndef MYOBJECT_H #define MYOBJECT_H #include + #include class MyObject : public node::ObjectWrap { public: static void Init(); - static v8::Handle NewInstance(const v8::Arguments& args); + static void NewInstance(const v8::FunctionCallbackInfo& args); private: explicit MyObject(double value = 0); ~MyObject(); - static v8::Handle New(const v8::Arguments& args); - static v8::Handle PlusOne(const v8::Arguments& args); + static void New(const v8::FunctionCallbackInfo& args); + static void PlusOne(const v8::FunctionCallbackInfo& args); static v8::Persistent constructor; double value_; }; @@ -468,6 +477,7 @@ care of instantiating the object (i.e. it does the job of `new` in JavaScript): The implementation is similar to the above in `myobject.cc`: + // myobject.cc #include #include "myobject.h" @@ -485,17 +495,16 @@ The implementation is similar to the above in `myobject.cc`: Isolate* isolate = Isolate::GetCurrent(); // Prepare constructor template Local tpl = FunctionTemplate::New(New); - tpl->SetClassName(String::NewSymbol("MyObject")); + tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype - tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"), - FunctionTemplate::New(PlusOne)->GetFunction()); + NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne); - constructor = Persistent::New(isolate, tpl->GetFunction()); + constructor.Reset(isolate, tpl->GetFunction()); } - Handle MyObject::New(const Arguments& args) { + void MyObject::New(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); @@ -504,38 +513,41 @@ The implementation is similar to the above in `myobject.cc`: double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); MyObject* obj = new MyObject(value); obj->Wrap(args.This()); - return args.This(); + args.GetReturnValue().Set(args.This()); } else { // Invoked as plain function `MyObject(...)`, turn into construct call. const int argc = 1; Local argv[argc] = { args[0] }; - return scope.Close(constructor->NewInstance(argc, argv)); + Local cons = Local::New(isolate, constructor); + args.GetReturnValue().Set(cons->NewInstance(argc, argv)); } } - Handle MyObject::NewInstance(const Arguments& args) { + void MyObject::NewInstance(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); const unsigned argc = 1; Handle argv[argc] = { args[0] }; - Local instance = constructor->NewInstance(argc, argv); + Local cons = Local::New(isolate, constructor); + Local instance = cons->NewInstance(argc, argv); - return scope.Close(instance); + args.GetReturnValue().Set(instance); } - Handle MyObject::PlusOne(const Arguments& args) { + void MyObject::PlusOne(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); MyObject* obj = ObjectWrap::Unwrap(args.This()); obj->value_ += 1; - return scope.Close(Number::New(obj->value_)); + args.GetReturnValue().Set(Number::New(obj->value_)); } Test it with: + // test.js var createObject = require('./build/Release/addon'); var obj = createObject(10); @@ -556,19 +568,20 @@ by unwrapping them with Node's `node::ObjectWrap::Unwrap` helper function. In the following `addon.cc` we introduce a function `add()` that can take on two `MyObject` objects: + // addon.cc #include #include #include "myobject.h" using namespace v8; - Handle CreateObject(const Arguments& args) { + void CreateObject(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); - return scope.Close(MyObject::NewInstance(args)); + MyObject::NewInstance(args); } - Handle Add(const Arguments& args) { + void Add(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); @@ -577,18 +590,15 @@ In the following `addon.cc` we introduce a function `add()` that can take on two MyObject* obj2 = node::ObjectWrap::Unwrap( args[1]->ToObject()); - double sum = obj1->Value() + obj2->Value(); - return scope.Close(Number::New(sum)); + double sum = obj1->value() + obj2->value(); + args.GetReturnValue().Set(Number::New(sum)); } void InitAll(Handle exports) { MyObject::Init(); - exports->Set(String::NewSymbol("createObject"), - FunctionTemplate::New(CreateObject)->GetFunction()); - - exports->Set(String::NewSymbol("add"), - FunctionTemplate::New(Add)->GetFunction()); + NODE_SET_METHOD(exports, "createObject", CreateObject); + NODE_SET_METHOD(exports, "add", Add); } NODE_MODULE(addon, InitAll) @@ -596,6 +606,7 @@ In the following `addon.cc` we introduce a function `add()` that can take on two To make things interesting we introduce a public method in `myobject.h` so we can probe private values after unwrapping the object: + // myobject.h #ifndef MYOBJECT_H #define MYOBJECT_H @@ -605,14 +616,14 @@ can probe private values after unwrapping the object: class MyObject : public node::ObjectWrap { public: static void Init(); - static v8::Handle NewInstance(const v8::Arguments& args); - double Value() const { return value_; } + static void NewInstance(const v8::FunctionCallbackInfo& args); + inline double value() const { return value_; } private: explicit MyObject(double value = 0); ~MyObject(); - static v8::Handle New(const v8::Arguments& args); + static void New(const v8::FunctionCallbackInfo& args); static v8::Persistent constructor; double value_; }; @@ -621,6 +632,7 @@ can probe private values after unwrapping the object: The implementation of `myobject.cc` is similar as before: + // myobject.cc #include #include "myobject.h" @@ -639,13 +651,13 @@ The implementation of `myobject.cc` is similar as before: // Prepare constructor template Local tpl = FunctionTemplate::New(New); - tpl->SetClassName(String::NewSymbol("MyObject")); + tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); tpl->InstanceTemplate()->SetInternalFieldCount(1); - constructor = Persistent::New(isolate, tpl->GetFunction()); + constructor.Reset(isolate, tpl->GetFunction()); } - Handle MyObject::New(const Arguments& args) { + void MyObject::New(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); @@ -654,28 +666,31 @@ The implementation of `myobject.cc` is similar as before: double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); MyObject* obj = new MyObject(value); obj->Wrap(args.This()); - return args.This(); + args.GetReturnValue().Set(args.This()); } else { // Invoked as plain function `MyObject(...)`, turn into construct call. const int argc = 1; Local argv[argc] = { args[0] }; - return scope.Close(constructor->NewInstance(argc, argv)); + Local cons = Local::New(isolate, constructor); + args.GetReturnValue().Set(cons->NewInstance(argc, argv)); } } - Handle MyObject::NewInstance(const Arguments& args) { + void MyObject::NewInstance(const FunctionCallbackInfo& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); const unsigned argc = 1; Handle argv[argc] = { args[0] }; - Local instance = constructor->NewInstance(argc, argv); + Local cons = Local::New(isolate, constructor); + Local instance = cons->NewInstance(argc, argv); - return scope.Close(instance); + args.GetReturnValue().Set(instance); } Test it with: + // test.js var addon = require('./build/Release/addon'); var obj1 = addon.createObject(10); diff --git a/test/addons/async-hello-world/binding.cc b/test/addons/async-hello-world/binding.cc index d0303f7aecc..02584c1abd8 100644 --- a/test/addons/async-hello-world/binding.cc +++ b/test/addons/async-hello-world/binding.cc @@ -13,21 +13,23 @@ struct async_req { Persistent callback; }; -void DoAsync (uv_work_t *r) { - async_req *req = reinterpret_cast(r->data); +void DoAsync(uv_work_t* r) { + async_req* req = reinterpret_cast(r->data); sleep(1); // simulate CPU intensive process... req->output = req->input * 2; } -void AfterAsync (uv_work_t *r) { - HandleScope scope; - async_req *req = reinterpret_cast(r->data); +void AfterAsync(uv_work_t* r) { + Isolate* isolate = Isolate::GetCurrent(); + HandleScope scope(isolate); + async_req* req = reinterpret_cast(r->data); Handle argv[2] = { Null(), Integer::New(req->output) }; TryCatch try_catch; - req->callback->Call(Context::GetCurrent()->Global(), 2, argv); + Local callback = Local::New(isolate, req->callback); + callback->Call(Context::GetCurrent()->Global(), 2, argv); // cleanup req->callback.Dispose(); @@ -38,24 +40,23 @@ void AfterAsync (uv_work_t *r) { } } -Handle Method(const Arguments& args) { - HandleScope scope; +void Method(const FunctionCallbackInfo& args) { + Isolate* isolate = Isolate::GetCurrent(); + HandleScope scope(isolate); - async_req *req = new async_req; + async_req* req = new async_req; req->req.data = req; req->input = args[0]->IntegerValue(); req->output = 0; Local callback = Local::Cast(args[1]); - req->callback = Persistent::New(callback); + req->callback.Reset(isolate, callback); uv_queue_work(uv_default_loop(), &req->req, DoAsync, (uv_after_work_cb)AfterAsync); - - return Undefined(); } void init(Handle exports, Handle module) { diff --git a/test/addons/at-exit/binding.cc b/test/addons/at-exit/binding.cc index 6558a08bf9e..3609e4d19c4 100644 --- a/test/addons/at-exit/binding.cc +++ b/test/addons/at-exit/binding.cc @@ -7,6 +7,7 @@ using node::AtExit; using v8::Handle; using v8::HandleScope; +using v8::Isolate; using v8::Local; using v8::Object; @@ -15,7 +16,7 @@ static int at_exit_cb1_called = 0; static int at_exit_cb2_called = 0; static void at_exit_cb1(void* arg) { - HandleScope scope; + HandleScope scope(Isolate::GetCurrent()); assert(arg == 0); Local obj = Object::New(); assert(!obj.IsEmpty()); // assert VM is still alive diff --git a/test/addons/hello-world-function-export/binding.cc b/test/addons/hello-world-function-export/binding.cc index dcdb6b8ce85..91fc26cef65 100644 --- a/test/addons/hello-world-function-export/binding.cc +++ b/test/addons/hello-world-function-export/binding.cc @@ -3,9 +3,10 @@ using namespace v8; -Handle Method(const Arguments& args) { - HandleScope scope; - return scope.Close(String::New("world")); +void Method(const FunctionCallbackInfo& args) { + Isolate* isolate = Isolate::GetCurrent(); + HandleScope scope(isolate); + args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world")); } void init(Handle exports, Handle module) { diff --git a/test/addons/hello-world/binding.cc b/test/addons/hello-world/binding.cc index 424fad8445a..1a6d179abe2 100644 --- a/test/addons/hello-world/binding.cc +++ b/test/addons/hello-world/binding.cc @@ -3,9 +3,10 @@ using namespace v8; -Handle Method(const Arguments& args) { - HandleScope scope; - return scope.Close(String::New("world")); +void Method(const FunctionCallbackInfo& args) { + Isolate* isolate = Isolate::GetCurrent(); + HandleScope scope(isolate); + args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world")); } void init(Handle target) { diff --git a/test/addons/testcfg.py b/test/addons/testcfg.py new file mode 100644 index 00000000000..908fd6a475c --- /dev/null +++ b/test/addons/testcfg.py @@ -0,0 +1,6 @@ +import sys, os +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) +import testpy + +def GetConfiguration(context, root): + return testpy.AddonTestConfiguration(context, root, 'addon') diff --git a/test/testpy/__init__.py b/test/testpy/__init__.py index 54b0f19916f..9593a1f6428 100644 --- a/test/testpy/__init__.py +++ b/test/testpy/__init__.py @@ -134,3 +134,28 @@ class SimpleTestConfiguration(test.TestConfiguration): status_file = join(self.root, '%s.status' % (self.section)) if exists(status_file): test.ReadConfigurationInto(status_file, sections, defs) + +class AddonTestConfiguration(SimpleTestConfiguration): + def __init__(self, context, root, section, additional=[]): + super(AddonTestConfiguration, self).__init__(context, root, section) + + def Ls(self, path): + def SelectTest(name): + return name.endswith('.js') + + result = [] + for subpath in os.listdir(path): + if os.path.isdir(join(path, subpath)): + for f in os.listdir(join(path, subpath)): + if SelectTest(f): + result.append([subpath, f[:-3]]) + return result + + def ListTests(self, current_path, path, mode): + all_tests = [current_path + t for t in self.Ls(join(self.root))] + result = [] + for test in all_tests: + if self.Contains(path, test): + file_path = join(self.root, reduce(join, test[1:], "") + ".js") + result.append(SimpleTestCase(test, file_path, mode, self.context, self)) + return result diff --git a/tools/doc/addon-verify.js b/tools/doc/addon-verify.js new file mode 100644 index 00000000000..f87cfecdf5f --- /dev/null +++ b/tools/doc/addon-verify.js @@ -0,0 +1,94 @@ +var fs = require('fs'); +var path = require('path'); +var marked = require('marked'); + +var doc = path.resolve(__dirname, '..', '..', 'doc', 'api', 'addons.markdown'); +var verifyDir = path.resolve(__dirname, '..', '..', 'test', 'addons'); + +var contents = fs.readFileSync(doc).toString(); + +var tokens = marked.lexer(contents, {}); +var files = null; +var id = 0; + +// Just to make sure that all examples will be processed +tokens.push({ type: 'heading' }); + +var oldDirs = fs.readdirSync(verifyDir); +oldDirs = oldDirs.filter(function(dir) { + return /^doc-/.test(dir); +}).map(function(dir) { + return path.resolve(verifyDir, dir); +}); + +for (var i = 0; i < tokens.length; i++) { + var token = tokens[i]; + if (token.type === 'heading') { + if (files && Object.keys(files).length !== 0) { + verifyFiles(files, function(err) { + if (err) + console.log(err); + else + console.log('done'); + }); + } + files = {}; + } else if (token.type === 'code') { + var match = token.text.match(/^\/\/\s+(.*\.(?:cc|h|js))[\r\n]/); + if (match === null) + continue; + files[match[1]] = token.text; + } +} + +function once(fn) { + var once = false; + return function() { + if (once) + return; + once = true; + fn.apply(this, arguments); + }; +} + +function verifyFiles(files, callback) { + var dir = path.resolve(verifyDir, 'doc-' + id++); + + files = Object.keys(files).map(function(name) { + return { + path: path.resolve(dir, name), + name: name, + content: files[name] + }; + }); + files.push({ + path: path.resolve(dir, 'binding.gyp'), + content: JSON.stringify({ + targets: [ + { + target_name: 'addon', + sources: files.map(function(file) { + return file.name; + }) + } + ] + }) + }); + + fs.mkdir(dir, function() { + // Ignore errors + + var waiting = files.length; + for (var i = 0; i < files.length; i++) + fs.writeFile(files[i].path, files[i].content, next); + + var done = once(callback); + function next(err) { + if (err) + return done(err); + + if (--waiting === 0) + done(); + } + }); +} -- cgit v1.2.3