diff --git a/src/node_jsvmapi.cc b/src/node_jsvmapi.cc index c21c3a925f4728..86a9de0b09776d 100644 --- a/src/node_jsvmapi.cc +++ b/src/node_jsvmapi.cc @@ -1951,24 +1951,32 @@ napi_status napi_get_and_clear_last_exception(napi_env e, napi_value* result) { return napi_ok; } -napi_status napi_buffer_new(napi_env e, char* data, size_t size, napi_value* result) { +napi_status napi_create_buffer(napi_env e, size_t size, char** data, + napi_value* result) { NAPI_PREAMBLE(e); + CHECK_ARG(data); CHECK_ARG(result); - auto maybe = node::Buffer::New(v8impl::V8IsolateFromJsEnv(e), data, size); + auto maybe = node::Buffer::New(v8impl::V8IsolateFromJsEnv(e), size); CHECK_MAYBE_EMPTY(maybe, napi_generic_failure); - *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked()); + v8::Local jsBuffer = maybe.ToLocalChecked(); + + *result = v8impl::JsValueFromV8LocalValue(jsBuffer); + *data = node::Buffer::Data(jsBuffer); + return GET_RETURN_STATUS(); } -napi_status napi_buffer_copy(napi_env e, const char* data, - size_t size, napi_value* result) { +napi_status napi_create_external_buffer(napi_env e, size_t size, char* data, + napi_finalize finalize_cb, + napi_value* result) { NAPI_PREAMBLE(e); CHECK_ARG(result); - auto maybe = node::Buffer::Copy(v8impl::V8IsolateFromJsEnv(e), data, size); + auto maybe = node::Buffer::New(v8impl::V8IsolateFromJsEnv(e), data, size, + (node::Buffer::FreeCallback)finalize_cb, nullptr); CHECK_MAYBE_EMPTY(maybe, napi_generic_failure); @@ -1976,27 +1984,41 @@ napi_status napi_buffer_copy(napi_env e, const char* data, return GET_RETURN_STATUS(); } -napi_status napi_buffer_has_instance(napi_env e, napi_value v, bool* result) { +napi_status napi_create_buffer_copy(napi_env e, const char* data, + size_t size, napi_value* result) { NAPI_PREAMBLE(e); CHECK_ARG(result); - *result = node::Buffer::HasInstance(v8impl::V8LocalValueFromJsValue(v)); + auto maybe = node::Buffer::Copy(v8impl::V8IsolateFromJsEnv(e), data, size); + + CHECK_MAYBE_EMPTY(maybe, napi_generic_failure); + + *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked()); return GET_RETURN_STATUS(); } -napi_status napi_buffer_data(napi_env e, napi_value v, char** result) { +napi_status napi_is_buffer(napi_env e, napi_value v, bool* result) { NAPI_PREAMBLE(e); CHECK_ARG(result); - *result = node::Buffer::Data(v8impl::V8LocalValueFromJsValue(v).As()); + *result = node::Buffer::HasInstance(v8impl::V8LocalValueFromJsValue(v)); return GET_RETURN_STATUS(); } -napi_status napi_buffer_length(napi_env e, napi_value v, size_t* result) { +napi_status napi_get_buffer_info(napi_env e, napi_value v, char** data, + size_t* length) { NAPI_PREAMBLE(e); - CHECK_ARG(result); - *result = node::Buffer::Length(v8impl::V8LocalValueFromJsValue(v)); + v8::Local buffer = + v8impl::V8LocalValueFromJsValue(v).As(); + + if (data) { + *data = node::Buffer::Data(buffer); + } + if (length) { + *length = node::Buffer::Length(buffer); + } + return GET_RETURN_STATUS(); } diff --git a/src/node_jsvmapi.h b/src/node_jsvmapi.h index 8917d99f013610..7cf6d3e28748fd 100644 --- a/src/node_jsvmapi.h +++ b/src/node_jsvmapi.h @@ -315,17 +315,21 @@ NODE_EXTERN napi_status napi_is_exception_pending(napi_env e, bool* result); NODE_EXTERN napi_status napi_get_and_clear_last_exception(napi_env e, napi_value* result); // Methods to provide node::Buffer functionality with napi types -NODE_EXTERN napi_status napi_buffer_new(napi_env e, - char* data, - size_t size, - napi_value* result); -NODE_EXTERN napi_status napi_buffer_copy(napi_env e, - const char* data, - size_t size, - napi_value* result); -NODE_EXTERN napi_status napi_buffer_has_instance(napi_env e, napi_value v, bool* result); -NODE_EXTERN napi_status napi_buffer_data(napi_env e, napi_value v, char** result); -NODE_EXTERN napi_status napi_buffer_length(napi_env e, napi_value v, size_t* result); +NODE_EXTERN napi_status napi_create_buffer(napi_env e, + size_t size, + char** data, + napi_value* result); +NODE_EXTERN napi_status napi_create_external_buffer(napi_env e, + size_t size, + char* data, + napi_finalize finalize_cb, + napi_value* result); +NODE_EXTERN napi_status napi_create_buffer_copy(napi_env e, + const char* data, + size_t size, + napi_value* result); +NODE_EXTERN napi_status napi_is_buffer(napi_env e, napi_value v, bool* result); +NODE_EXTERN napi_status napi_get_buffer_info(napi_env e, napi_value v, char** data, size_t* length); // Methods to work with array buffers and typed arrays NODE_EXTERN napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result); diff --git a/test/addons-abi/1_hello_world/test.js b/test/addons-abi/1_hello_world/test.js index 85d7402c780fda..d349dcfbd9a803 100644 --- a/test/addons-abi/1_hello_world/test.js +++ b/test/addons-abi/1_hello_world/test.js @@ -1,6 +1,6 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); -var addon = require('./build/Release/binding'); +var addon = require(`./build/${common.buildType}/binding`); assert.equal(addon.hello(), 'world'); diff --git a/test/addons-abi/2_function_arguments/test.js b/test/addons-abi/2_function_arguments/test.js index b0e11759636e80..dcdb365bcc0bc9 100644 --- a/test/addons-abi/2_function_arguments/test.js +++ b/test/addons-abi/2_function_arguments/test.js @@ -1,6 +1,6 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); -var addon = require('./build/Release/binding'); +var addon = require(`./build/${common.buildType}/binding`); assert.equal(addon.add(3, 5), 8); diff --git a/test/addons-abi/3_callbacks/test.js b/test/addons-abi/3_callbacks/test.js index c3bbc1e7e9ba3d..4e8f0854136ebb 100644 --- a/test/addons-abi/3_callbacks/test.js +++ b/test/addons-abi/3_callbacks/test.js @@ -1,7 +1,7 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); -var addon = require('./build/Release/binding'); +var addon = require(`./build/${common.buildType}/binding`); addon.RunCallback(function(msg) { assert.equal(msg, 'hello world'); diff --git a/test/addons-abi/4_object_factory/test.js b/test/addons-abi/4_object_factory/test.js index 7c0cc56432a96a..5581dd12ce596b 100644 --- a/test/addons-abi/4_object_factory/test.js +++ b/test/addons-abi/4_object_factory/test.js @@ -1,7 +1,7 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); -var addon = require('./build/Release/binding'); +var addon = require(`./build/${common.buildType}/binding`); var obj1 = addon('hello'); var obj2 = addon('world'); diff --git a/test/addons-abi/5_function_factory/test.js b/test/addons-abi/5_function_factory/test.js index 8468d76905fadf..954bc0ce020db4 100644 --- a/test/addons-abi/5_function_factory/test.js +++ b/test/addons-abi/5_function_factory/test.js @@ -1,7 +1,7 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); -var addon = require('./build/Release/binding'); +var addon = require(`./build/${common.buildType}/binding`); var fn = addon(); assert.equal(fn(), 'hello world'); // 'hello world' diff --git a/test/addons-abi/6_object_wrap/test.js b/test/addons-abi/6_object_wrap/test.js index 05addfa3a1083d..210fa909d9a32f 100644 --- a/test/addons-abi/6_object_wrap/test.js +++ b/test/addons-abi/6_object_wrap/test.js @@ -1,7 +1,7 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); -var addon = require('./build/Release/binding'); +var addon = require(`./build/${common.buildType}/binding`); var obj = new addon.MyObject(9); assert.equal(obj.value, 9); diff --git a/test/addons-abi/7_factory_wrap/test.js b/test/addons-abi/7_factory_wrap/test.js index 561464b66c37ee..e69b03ce9a4fbe 100644 --- a/test/addons-abi/7_factory_wrap/test.js +++ b/test/addons-abi/7_factory_wrap/test.js @@ -1,7 +1,7 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); -var createObject = require('./build/Release/binding'); +var createObject = require(`./build/${common.buildType}/binding`); var obj = createObject(10); assert.equal(obj.plusOne(), 11); diff --git a/test/addons-abi/8_passing_wrapped/test.js b/test/addons-abi/8_passing_wrapped/test.js index afb247eaf297ed..ee42f501825178 100644 --- a/test/addons-abi/8_passing_wrapped/test.js +++ b/test/addons-abi/8_passing_wrapped/test.js @@ -1,7 +1,7 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); -var addon = require('./build/Release/binding'); +var addon = require(`./build/${common.buildType}/binding`); var obj1 = addon.createObject(10); var obj2 = addon.createObject(20); diff --git a/test/addons-abi/test_array/test.js b/test/addons-abi/test_array/test.js index 1713684395f783..7168786993d763 100644 --- a/test/addons-abi/test_array/test.js +++ b/test/addons-abi/test_array/test.js @@ -1,9 +1,9 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); // Testing api calls for arrays -var test_array = require('./build/Release/test_array'); +var test_array = require(`./build/${common.buildType}/test_array`); var array = [ 1, diff --git a/test/addons-abi/test_buffer/binding.gyp b/test/addons-abi/test_buffer/binding.gyp new file mode 100644 index 00000000000000..711edd4f792168 --- /dev/null +++ b/test/addons-abi/test_buffer/binding.gyp @@ -0,0 +1,8 @@ +{ + "targets": [ + { + "target_name": "test_buffer", + "sources": [ "test_buffer.cc" ] + } + ] +} diff --git a/test/addons-abi/test_buffer/test.js b/test/addons-abi/test_buffer/test.js new file mode 100644 index 00000000000000..775694f2fb1cd8 --- /dev/null +++ b/test/addons-abi/test_buffer/test.js @@ -0,0 +1,24 @@ +'use strict'; +// Flags: --expose-gc + +var common = require('../../common'); +var binding = require(`./build/${common.buildType}/test_buffer`); +var assert = require( "assert" ); + +assert( binding.newBuffer().toString() === binding.theText, + "buffer returned by newBuffer() has wrong contents" ); +assert( binding.newExternalBuffer().toString() === binding.theText, + "buffer returned by newExternalBuffer() has wrong contents" ); +console.log( "gc1" ); +global.gc(); +assert( binding.getDeleterCallCount(), 1, "deleter was not called" ); +assert( binding.copyBuffer().toString() === binding.theText, + "buffer returned by copyBuffer() has wrong contents" ); + +var buffer = binding.staticBuffer(); +assert( binding.bufferHasInstance( buffer ), true, "buffer type checking fails" ); +assert( binding.bufferInfo( buffer ), true, "buffer data is accurate" ); +buffer = null; +global.gc(); +console.log( "gc2" ); +assert( binding.getDeleterCallCount(), 2, "deleter was not called" ); diff --git a/test/addons-abi/test_buffer/test_buffer.cc b/test/addons-abi/test_buffer/test_buffer.cc new file mode 100644 index 00000000000000..0ca455e6ae35e0 --- /dev/null +++ b/test/addons-abi/test_buffer/test_buffer.cc @@ -0,0 +1,128 @@ +#include +#include +#include + +#define JS_ASSERT(env, assertion, message) \ + if (!(assertion)) { \ + napi_throw_error((env), (std::string("assertion (" #assertion ") failed: ") + message).c_str()); \ + return; \ + } + +#define NAPI_CALL(env, theCall) \ + if (theCall != napi_ok) { \ + const char *errorMessage = napi_get_last_error_info()->error_message; \ + errorMessage = errorMessage ? errorMessage: "empty error message"; \ + napi_throw_error((env), errorMessage); \ + return; \ + } + +static const char theText[] = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit."; + +static int deleterCallCount = 0; +static void deleteTheText(void *data) { + delete (char *)data; + deleterCallCount++; +} + +static void noopDeleter(void *data) { + deleterCallCount++; +} + +NAPI_METHOD(newBuffer) { + napi_value theBuffer; + char *theCopy; + NAPI_CALL(env, napi_create_buffer(env, sizeof(theText), &theCopy, + &theBuffer)); + JS_ASSERT(env, theCopy, "Failed to copy static text for newBuffer"); + strcpy(theCopy, theText); + NAPI_CALL(env, napi_set_return_value(env, info, theBuffer)); +} + +NAPI_METHOD(newExternalBuffer) { + napi_value theBuffer; + char *theCopy = strdup(theText); + JS_ASSERT(env, theCopy, + "Failed to copy static text for newExternalBuffer"); + NAPI_CALL(env, napi_create_external_buffer(env, sizeof(theText), theCopy, + deleteTheText, &theBuffer)); + NAPI_CALL(env, napi_set_return_value(env, info, theBuffer)); +} + +NAPI_METHOD(getDeleterCallCount) { + napi_value callCount; + NAPI_CALL(env, napi_create_number(env, deleterCallCount, &callCount)); + NAPI_CALL(env, napi_set_return_value(env, info, callCount)); +} + +NAPI_METHOD(copyBuffer) { + napi_value theBuffer; + NAPI_CALL(env, napi_create_buffer_copy(env, theText, sizeof(theText), + &theBuffer)); + NAPI_CALL(env, napi_set_return_value(env, info, theBuffer)); +} + +NAPI_METHOD(bufferHasInstance) { + int argc; + NAPI_CALL(env, napi_get_cb_args_length(env, info, &argc)); + JS_ASSERT(env, argc == 1, "Wrong number of arguments"); + napi_value theBuffer; + NAPI_CALL(env, napi_get_cb_args(env, info, &theBuffer, 1)); + bool hasInstance; + napi_valuetype theType; + NAPI_CALL(env, napi_get_type_of_value(env, theBuffer, &theType)); + JS_ASSERT(env, theType == napi_object, + "bufferHasInstance: instance is not an object"); + NAPI_CALL(env, napi_is_buffer(env, theBuffer, &hasInstance)); + JS_ASSERT(env, hasInstance, "bufferHasInstance: instance is not a buffer"); + napi_value returnValue; + NAPI_CALL(env, napi_create_boolean(env, hasInstance, &returnValue)); + NAPI_CALL(env, napi_set_return_value(env, info, returnValue)); +} + +NAPI_METHOD(bufferInfo) { + int argc; + NAPI_CALL(env, napi_get_cb_args_length(env, info, &argc)); + JS_ASSERT(env, argc == 1, "Wrong number of arguments"); + napi_value theBuffer, returnValue; + NAPI_CALL(env, napi_get_cb_args(env, info, &theBuffer, 1)); + char *bufferData; + size_t bufferLength; + NAPI_CALL(env, napi_get_buffer_info(env, theBuffer, &bufferData, + &bufferLength)); + NAPI_CALL(env, napi_create_boolean(env, + !strcmp(bufferData, theText) && bufferLength == sizeof(theText), + &returnValue)); + NAPI_CALL(env, napi_set_return_value(env, info, returnValue)); +} + +NAPI_METHOD(staticBuffer) { + napi_value theBuffer; + NAPI_CALL(env, napi_create_external_buffer(env, sizeof(theText), + (char *)theText, noopDeleter, &theBuffer)); + NAPI_CALL(env, napi_set_return_value(env, info, theBuffer)); +} + +void Init(napi_env env, napi_value exports, napi_value module) { + napi_propertyname propName; + napi_value theValue; + + NAPI_CALL(env, napi_property_name(env, "theText", &propName)); + NAPI_CALL(env, napi_create_string_utf8(env, theText, sizeof(theText), &theValue)); + NAPI_CALL(env, napi_set_property(env, exports, propName, theValue)); + + napi_property_descriptor methods[] = { + { "newBuffer", newBuffer }, + { "newExternalBuffer", newExternalBuffer }, + { "getDeleterCallCount", getDeleterCallCount }, + { "copyBuffer", copyBuffer }, + { "bufferHasInstance", bufferHasInstance }, + { "bufferInfo", bufferInfo }, + { "staticBuffer", staticBuffer } + }; + + NAPI_CALL(env, napi_define_properties(env, exports, + sizeof(methods)/sizeof(methods[0]), methods)); +} + +NODE_MODULE_ABI(addon, Init) diff --git a/test/addons-abi/test_constructor/test.js b/test/addons-abi/test_constructor/test.js index 66089c2ea54f7e..25733573a96e74 100644 --- a/test/addons-abi/test_constructor/test.js +++ b/test/addons-abi/test_constructor/test.js @@ -1,9 +1,9 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); // Testing api calls for a constructor that defines properties -var TestConstructor = require('./build/Release/test_constructor'); +var TestConstructor = require(`./build/${common.buildType}/test_constructor`); var test_object = new TestConstructor(); assert.equal(test_object.echo('hello'), 'hello'); diff --git a/test/addons-abi/test_exception/test.js b/test/addons-abi/test_exception/test.js index bc6866ab93f113..02ebabd6961650 100644 --- a/test/addons-abi/test_exception/test.js +++ b/test/addons-abi/test_exception/test.js @@ -1,6 +1,7 @@ 'use strict'; -var test_exception = require( "./build/Release/test_exception" ); +var common = require('../../common'); +var test_exception = require(`./build/${common.buildType}/test_exception`); var assert = require( "assert" ); var theError = new Error( "Some error" ); var throwTheError = function() { diff --git a/test/addons-abi/test_function/test.js b/test/addons-abi/test_function/test.js index 05446a361ed8d9..7351519a205d1c 100644 --- a/test/addons-abi/test_function/test.js +++ b/test/addons-abi/test_function/test.js @@ -1,9 +1,9 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); // testing api calls for function -var test_function = require('./build/Release/test_function'); +var test_function = require(`./build/${common.buildType}/test_function`); function func1() { diff --git a/test/addons-abi/test_instanceof/test.js b/test/addons-abi/test_instanceof/test.js index 022c912945e504..1a9b126a7fb71c 100644 --- a/test/addons-abi/test_instanceof/test.js +++ b/test/addons-abi/test_instanceof/test.js @@ -1,8 +1,8 @@ var fs = require( 'fs' ); -require('../../common'); +var common = require('../../common'); var assert = require('assert'); -var addon = require('./build/Release/test_instanceof'); +var addon = require(`./build/${common.buildType}/test_instanceof`); var path = require( 'path' ); function assertTrue(assertion) { diff --git a/test/addons-abi/test_number/test.js b/test/addons-abi/test_number/test.js index 2198da400006b2..76bff04ce10332 100644 --- a/test/addons-abi/test_number/test.js +++ b/test/addons-abi/test_number/test.js @@ -1,7 +1,7 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); -var test_number = require('./build/Release/test_number'); +var test_number = require(`./build/${common.buildType}/test_number`); // testing api calls for number diff --git a/test/addons-abi/test_object/test.js b/test/addons-abi/test_object/test.js index 7c99e3d24b062b..4a40c0961f8ec1 100644 --- a/test/addons-abi/test_object/test.js +++ b/test/addons-abi/test_object/test.js @@ -1,9 +1,9 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); // Testing api calls for objects -var test_object = require('./build/Release/test_object'); +var test_object = require(`./build/${common.buildType}/test_object`); var object = { diff --git a/test/addons-abi/test_properties/test.js b/test/addons-abi/test_properties/test.js index 407eae3271ed41..a32dc7bc321a95 100644 --- a/test/addons-abi/test_properties/test.js +++ b/test/addons-abi/test_properties/test.js @@ -1,9 +1,9 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); // Testing api calls for defining properties -var test_object = require('./build/Release/test_properties'); +var test_object = require(`./build/${common.buildType}/test_properties`); assert.equal(test_object.echo('hello'), 'hello'); diff --git a/test/addons-abi/test_string/test.js b/test/addons-abi/test_string/test.js index d3c397845c92f3..b489ad3d3708d1 100644 --- a/test/addons-abi/test_string/test.js +++ b/test/addons-abi/test_string/test.js @@ -1,9 +1,9 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); // testing api calls for string -var test_string = require('./build/Release/test_string'); +var test_string = require(`./build/${common.buildType}/test_string`); var str1 = 'hello world'; assert.equal(test_string.Copy(str1), str1); diff --git a/test/addons-abi/test_symbol/test1.js b/test/addons-abi/test_symbol/test1.js index 8846c221291700..77e26983351001 100644 --- a/test/addons-abi/test_symbol/test1.js +++ b/test/addons-abi/test_symbol/test1.js @@ -1,9 +1,9 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); // testing api calls for symbol -var test_symbol = require('./build/Release/test_symbol'); +var test_symbol = require(`./build/${common.buildType}/test_symbol`); var sym = test_symbol.New('test'); assert.equal(sym.toString(), 'Symbol(test)'); diff --git a/test/addons-abi/test_symbol/test2.js b/test/addons-abi/test_symbol/test2.js index 89a27f0355d7ba..c786584a76b2e2 100644 --- a/test/addons-abi/test_symbol/test2.js +++ b/test/addons-abi/test_symbol/test2.js @@ -1,9 +1,9 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); // testing api calls for symbol -var test_symbol = require('./build/Release/test_symbol'); +var test_symbol = require(`./build/${common.buildType}/test_symbol`); var fooSym = test_symbol.New('foo'); var myObj = {}; diff --git a/test/addons-abi/test_symbol/test3.js b/test/addons-abi/test_symbol/test3.js index 8a8cc6c3f77cb0..de76c0b87cb33f 100644 --- a/test/addons-abi/test_symbol/test3.js +++ b/test/addons-abi/test_symbol/test3.js @@ -1,9 +1,9 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); // testing api calls for symbol -var test_symbol = require('./build/Release/test_symbol'); +var test_symbol = require(`./build/${common.buildType}/test_symbol`); assert.notEqual(test_symbol.New(), test_symbol.New()); assert.notEqual(test_symbol.New('foo'), test_symbol.New('foo')); diff --git a/test/addons-abi/test_typedarray/test.js b/test/addons-abi/test_typedarray/test.js index e27273321d9426..2aa1960beac52c 100644 --- a/test/addons-abi/test_typedarray/test.js +++ b/test/addons-abi/test_typedarray/test.js @@ -1,9 +1,9 @@ 'use strict'; -require('../../common'); +var common = require('../../common'); var assert = require('assert'); // Testing api calls for arrays -var test_typedarray = require('./build/Release/test_typedarray'); +var test_typedarray = require(`./build/${common.buildType}/test_typedarray`); var byteArray = new Uint8Array(3); byteArray[0] = 0;