[Pkg-javascript-commits] [node-leveldown] 217/492: comprehensive put() tests, made put() more robust

Andrew Kelley andrewrk-guest at moszumanska.debian.org
Sun Jul 6 17:14:00 UTC 2014


This is an automated email from the git hooks/post-receive script.

andrewrk-guest pushed a commit to annotated tag rocksdb-0.10.1
in repository node-leveldown.

commit 4df762d3288cc3505f27d3b58bfb0d7f7b883687
Author: Rod Vagg <rod at vagg.org>
Date:   Sun Feb 17 16:33:24 2013 +1100

    comprehensive put() tests, made put() more robust
---
 src/database.cc        |  47 ++++++++---------
 src/iterator.cc        |   7 ++-
 src/leveldown.h        |  22 +++++++-
 test/data/testdata.bin | Bin 0 -> 4688 bytes
 test/put-test.js       | 134 +++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 183 insertions(+), 27 deletions(-)

diff --git a/src/database.cc b/src/database.cc
index 41d54e7..3a4dec6 100644
--- a/src/database.cc
+++ b/src/database.cc
@@ -205,18 +205,18 @@ v8::Handle<v8::Value> Database::Close (const v8::Arguments& args) {
 v8::Handle<v8::Value> Database::Put (const v8::Arguments& args) {
   v8::HandleScope scope;
 
-  Database* database = node::ObjectWrap::Unwrap<Database>(args.This());
-  v8::Persistent<v8::Function> callback =
-      v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(args[3]));
+  METHOD_SETUP_COMMON(put, 2, 3)
 
-  CB_ERR_IF_NULL_OR_UNDEFINED(0, "Key")
-  CB_ERR_IF_NULL_OR_UNDEFINED(1, "Value")
+  CB_ERR_IF_NULL_OR_UNDEFINED(0, Key)
+  CB_ERR_IF_NULL_OR_UNDEFINED(1, Value)
 
-  v8::Persistent<v8::Value> keyBuffer = v8::Persistent<v8::Value>::New(args[0]);
-  STRING_OR_BUFFER_TO_SLICE(key, keyBuffer)
-  v8::Persistent<v8::Value> valueBuffer = v8::Persistent<v8::Value>::New(args[1]);
-  STRING_OR_BUFFER_TO_SLICE(value, valueBuffer)
-  v8::Local<v8::Object> optionsObj = v8::Local<v8::Object>::Cast(args[2]);
+  v8::Local<v8::Value> keyBufferV = args[0];
+  v8::Local<v8::Value> valueBufferV = args[1];
+  STRING_OR_BUFFER_TO_SLICE(key, keyBufferV, Key)
+  STRING_OR_BUFFER_TO_SLICE(value, valueBufferV, Value)
+
+  v8::Persistent<v8::Value> keyBuffer = v8::Persistent<v8::Value>::New(keyBufferV);
+  v8::Persistent<v8::Value> valueBuffer = v8::Persistent<v8::Value>::New(valueBufferV);
   BOOLEAN_OPTION_VALUE(optionsObj, sync)
 
   WriteWorker* worker  = new WriteWorker(
@@ -236,15 +236,16 @@ v8::Handle<v8::Value> Database::Put (const v8::Arguments& args) {
 v8::Handle<v8::Value> Database::Get (const v8::Arguments& args) {
   v8::HandleScope scope;
 
-  Database* database = node::ObjectWrap::Unwrap<Database>(args.This());
-  v8::Persistent<v8::Function> callback =
-      v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(args[2]));
+  METHOD_SETUP_COMMON(put, 1, 2)
 
-  CB_ERR_IF_NULL_OR_UNDEFINED(0, "Key")
+  CB_ERR_IF_NULL_OR_UNDEFINED(0, Key)
+  CB_ERR_IF_NULL_OR_UNDEFINED(1, Value)
+
+  v8::Local<v8::Value> keyBufferV = args[0];
+  STRING_OR_BUFFER_TO_SLICE(key, keyBufferV, Key)
+
+  v8::Persistent<v8::Value> keyBuffer = v8::Persistent<v8::Value>::New(keyBufferV);
 
-  v8::Persistent<v8::Value> keyBuffer = v8::Persistent<v8::Value>::New(args[0]);
-  STRING_OR_BUFFER_TO_SLICE(key, keyBuffer)
-  v8::Local<v8::Object> optionsObj = v8::Local<v8::Object>::Cast(args[1]);
   BOOLEAN_OPTION_VALUE_DEFTRUE(optionsObj, asBuffer)
   BOOLEAN_OPTION_VALUE_DEFTRUE(optionsObj, fillCache)
 
@@ -271,7 +272,7 @@ v8::Handle<v8::Value> Database::Delete (const v8::Arguments& args) {
   CB_ERR_IF_NULL_OR_UNDEFINED(0, "Key")
 
   v8::Persistent<v8::Value> keyBuffer = v8::Persistent<v8::Value>::New(args[0]);
-  STRING_OR_BUFFER_TO_SLICE(key, keyBuffer)
+  STRING_OR_BUFFER_TO_SLICE(key, keyBuffer, Key)
   v8::Local<v8::Object> optionsObj = v8::Local<v8::Object>::Cast(args[1]);
   BOOLEAN_OPTION_VALUE(optionsObj, sync)
 
@@ -309,7 +310,7 @@ v8::Handle<v8::Value> Database::Batch (const v8::Arguments& args) {
     v8::Local<v8::Value> keyBuffer = obj->Get(str_key);
 
     if (obj->Get(str_type)->StrictEquals(str_del)) {
-      STRING_OR_BUFFER_TO_SLICE(key, keyBuffer)
+      STRING_OR_BUFFER_TO_SLICE(key, keyBuffer, Key)
       operations->push_back(new BatchDelete(
           key
         , v8::Persistent<v8::Value>::New(keyBuffer)
@@ -318,8 +319,8 @@ v8::Handle<v8::Value> Database::Batch (const v8::Arguments& args) {
       if (!obj->Has(str_value))
         continue;
       v8::Local<v8::Value> valueBuffer = obj->Get(str_value);
-      STRING_OR_BUFFER_TO_SLICE(key, keyBuffer)
-      STRING_OR_BUFFER_TO_SLICE(value, valueBuffer)
+      STRING_OR_BUFFER_TO_SLICE(key, keyBuffer, Key)
+      STRING_OR_BUFFER_TO_SLICE(value, valueBuffer, Value)
       operations->push_back(new BatchWrite(
           key
         , value
@@ -350,9 +351,9 @@ v8::Handle<v8::Value> Database::ApproximateSize (const v8::Arguments& args) {
   CB_ERR_IF_NULL_OR_UNDEFINED(1, "end")
 
   v8::Persistent<v8::Value> startBuffer = v8::Persistent<v8::Value>::New(args[0]);
-  STRING_OR_BUFFER_TO_SLICE(start, startBuffer)
+  STRING_OR_BUFFER_TO_SLICE(start, startBuffer, Start)
   v8::Persistent<v8::Value> endBuffer = v8::Persistent<v8::Value>::New(args[1]);
-  STRING_OR_BUFFER_TO_SLICE(end, endBuffer)
+  STRING_OR_BUFFER_TO_SLICE(end, endBuffer, End)
 
   ApproximateSizeWorker* worker  = new ApproximateSizeWorker(
       database
diff --git a/src/iterator.cc b/src/iterator.cc
index 0d71880..06dfec7 100644
--- a/src/iterator.cc
+++ b/src/iterator.cc
@@ -155,6 +155,9 @@ v8::Handle<v8::Value> Iterator::NewInstance (const v8::Arguments& args) {
 v8::Handle<v8::Value> Iterator::New (const v8::Arguments& args) {
   v8::HandleScope scope;
 
+  //TODO: remove this, it's only here to make STRING_OR_BUFFER_TO_SLICE happy
+  v8::Local<v8::Function> callback;
+
   Database* database = node::ObjectWrap::Unwrap<Database>(args[0]->ToObject());
   leveldb::Slice* start = NULL;
   if (args[1]->ToObject()->Has(option_start)
@@ -162,7 +165,7 @@ v8::Handle<v8::Value> Iterator::New (const v8::Arguments& args) {
         || args[1]->ToObject()->Get(option_start)->IsString())) {
     v8::Local<v8::Value> startBuffer =
       v8::Local<v8::Value>::New(args[1]->ToObject()->Get(option_start));
-    STRING_OR_BUFFER_TO_SLICE(_start, startBuffer)
+    STRING_OR_BUFFER_TO_SLICE(_start, startBuffer, Start)
     start = new leveldb::Slice(_start.data(), _start.size());
   }
   std::string* end = NULL;
@@ -171,7 +174,7 @@ v8::Handle<v8::Value> Iterator::New (const v8::Arguments& args) {
         || args[1]->ToObject()->Get(option_end)->IsString())) {
     v8::Local<v8::Value> endBuffer =
       v8::Local<v8::Value>::New(args[1]->ToObject()->Get(option_end));
-    STRING_OR_BUFFER_TO_SLICE(_end, endBuffer)
+    STRING_OR_BUFFER_TO_SLICE(_end, endBuffer, End)
     end = new std::string(_end.data(), _end.size());
   }
   v8::Local<v8::Object> optionsObj = v8::Local<v8::Object>::Cast(args[1]);
diff --git a/src/leveldown.h b/src/leveldown.h
index 8f2b46c..e1c886d 100644
--- a/src/leveldown.h
+++ b/src/leveldown.h
@@ -21,7 +21,7 @@
   if (args[index]->IsNull() || args[index]->IsUndefined()) { \
     v8::Local<v8::Value> argv[] = { \
       v8::Local<v8::Value>::New(v8::Exception::Error( \
-        v8::String::New("#name cannot be `null` or `undefined`")) \
+        v8::String::New(#name " argument cannot be `null` or `undefined`")) \
       ) \
     }; \
     RUN_CALLBACK(callback, argv, 1); \
@@ -36,15 +36,33 @@
   to = new char[to ## Sz_ + 1]; \
   to ## Str->WriteUtf8(to, -1, NULL, v8::String::NO_OPTIONS);
 
-#define STRING_OR_BUFFER_TO_SLICE(to, from) \
+#define STRING_OR_BUFFER_TO_SLICE(to, from, name) \
   size_t to ## Sz_; \
   char* to ## Ch_; \
   if (node::Buffer::HasInstance(from->ToObject())) { \
     to ## Sz_ = node::Buffer::Length(from->ToObject()); \
+    if (to ## Sz_ == 0) { \
+      v8::Local<v8::Value> argv[] = { \
+        v8::Local<v8::Value>::New(v8::Exception::Error( \
+          v8::String::New(#name " argument cannot be an empty Buffer")) \
+        ) \
+      }; \
+      RUN_CALLBACK(callback, argv, 1); \
+      return v8::Undefined(); \
+    } \
     to ## Ch_ = node::Buffer::Data(from->ToObject()); \
   } else { \
     v8::Local<v8::String> to ## Str = from->ToString(); \
     to ## Sz_ = to ## Str->Utf8Length(); \
+    if (to ## Sz_ == 0) { \
+      v8::Local<v8::Value> argv[] = { \
+        v8::Local<v8::Value>::New(v8::Exception::Error( \
+          v8::String::New(#name " argument cannot be an empty String")) \
+        ) \
+      }; \
+      RUN_CALLBACK(callback, argv, 1); \
+      return v8::Undefined(); \
+    } \
     to ## Ch_ = new char[to ## Sz_]; \
     to ## Str->WriteUtf8(to ## Ch_, -1, NULL, v8::String::NO_NULL_TERMINATION); \
   } \
diff --git a/test/data/testdata.bin b/test/data/testdata.bin
new file mode 100644
index 0000000..59229b9
Binary files /dev/null and b/test/data/testdata.bin differ
diff --git a/test/put-test.js b/test/put-test.js
new file mode 100644
index 0000000..c1a2d42
--- /dev/null
+++ b/test/put-test.js
@@ -0,0 +1,134 @@
+const fs         = require('fs')
+    , path       = require('path')
+    , test       = require('tap').test
+    , testCommon = require('./common')
+    , leveldown  = require('../')
+
+var db
+
+  , makePutErrorTest = function (type, key, value, expectedError) {
+      test('put() with ' + type + ' causes error', function (t) {
+        db.put(key, value, function (err) {
+          t.ok(err, 'has error')
+          t.type(err, Error)
+          t.like(err.message, expectedError, 'correct error message')
+          t.end()
+        })
+      })
+    }
+
+  , makePutTest = function (t, key, value, callback) {
+      db.put(key, value, function (err) {
+        t.notOk(err, 'no error')
+        db.get(key, function (err, _value) {
+          t.notOk(err, 'no error, has key/value for `' + key + '`')
+          t.equals(_value.toString(), value.toString())
+          callback()
+        })
+      })
+    }
+
+test('setUp', function (t) {
+  testCommon.setUp.apply(null, arguments)
+  db = leveldown(testCommon.location())
+  db.open(t.end.bind(t))
+})
+
+makePutErrorTest('null key', null, 'foo', /Key argument cannot be `null` or `undefined`/)
+makePutErrorTest('undefined key', undefined, 'foo', /Key argument cannot be `null` or `undefined`/)
+makePutErrorTest('empty String key', '', 'foo', /Key argument cannot be an empty String/)
+makePutErrorTest('empty Buffer key', new Buffer(0), 'foo', /Key argument cannot be an empty Buffer/)
+makePutErrorTest('empty Array key', [], 'foo', /Key argument cannot be an empty String/)
+
+test('put() with other falsey keys works', function (t) {
+  t.plan(9)
+
+  var done = function () {
+        if (++done.count == done.expected)
+          return t.end()
+      }
+
+    , testPut = function (key, value) {
+        done.expected++
+        makePutTest(t, key, value, done)
+      }
+
+  testPut(false, 'foo false')
+  testPut(0, 'foo 0')
+  testPut(NaN, 'foo NaN')
+})
+
+test('put() with plain String key works', function (t) {
+  makePutTest(
+      t
+    , 'some long string that I\'m using as a key for this unit test, cross your fingers dude, we\'re going in!'
+    , 'foo'
+    , t.end.bind(t)
+  )
+})
+
+test('put() with plain Buffer key works', function (t) {
+  fs.readFile(path.join(__dirname, 'data/testdata.bin'), function (err, data) {
+    t.notOk(err, 'read test data file')
+    t.type(data, Buffer)
+
+    makePutTest(
+        t
+      , data
+      , 'foo'
+      , t.end.bind(t)
+    )
+  })
+})
+
+makePutErrorTest('null value', 'foo', null, /Value argument cannot be `null` or `undefined`/)
+makePutErrorTest('undefined value', 'foo', undefined, /Value argument cannot be `null` or `undefined`/)
+makePutErrorTest('empty String value', 'foo', '', /Value argument cannot be an empty String/)
+makePutErrorTest('empty Buffer value', 'foo', new Buffer(0), /Value argument cannot be an empty Buffer/)
+makePutErrorTest('empty Array value', 'foo', [], /Value argument cannot be an empty String/)
+
+test('put() with other falsey values works', function (t) {
+  t.plan(9)
+
+  var done = function () {
+        if (++done.count == done.expected)
+          return t.end()
+      }
+
+    , testPut = function (key, value) {
+        done.expected++
+        makePutTest(t, key, value, done)
+      }
+
+  testPut('foo false', false)
+  testPut('foo 0', 0)
+  testPut('foo NaN', NaN)
+})
+
+test('put() with plain String value works', function (t) {
+  makePutTest(
+      t
+    , 'foo'
+    , 'some long string that I\'m using as a value for this unit test, cross your fingers dude, we\'re going in!'
+    , t.end.bind(t)
+  )
+})
+
+test('put() with plain Buffer value works', function (t) {
+  fs.readFile(path.join(__dirname, 'data/testdata.bin'), function (err, data) {
+    t.notOk(err, 'read test data file')
+    t.type(data, Buffer)
+
+    makePutTest(
+        t
+      , 'foo'
+      , data
+      , t.end.bind(t)
+    )
+  })
+})
+
+test('tearDown', function (t) {
+  testCommon.tearDown.apply(null, arguments)
+  db.close(t.end.bind(t))
+})
\ No newline at end of file

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-leveldown.git



More information about the Pkg-javascript-commits mailing list