diff --git a/.env b/.env deleted file mode 100644 index c10156b..0000000 --- a/.env +++ /dev/null @@ -1,4 +0,0 @@ -CACHE_MGR_PATH=/usr/local/Cache/mgr -CACHE_USERNAME= -CACHE_PASSWORD= -CACHE_NAMESPACE= \ No newline at end of file diff --git a/.env.sample b/.env.sample index e69de29..9be4af2 100644 --- a/.env.sample +++ b/.env.sample @@ -0,0 +1,4 @@ +CACHE_MGR_PATH=/usr/local/Cache/mgr +CACHE_USERNAME= +CACHE_PASSWORD= +CACHE_NAMESPACE= diff --git a/.gitignore b/.gitignore index 08c028e..e001356 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ npm-debug.log node_modules/ package-lock.json +*.lock # Sublime Text *.sublime-* diff --git a/.travis.yml b/.travis.yml index 0e2757b..737de95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,13 @@ language: node_js node_js: + - '11' + - '10' + - '9' - '8' - '7' - '6' - '5' - '4' - - 'iojs' - - '0.12' - - '0.11' - - '0.10' script: - npm run test:unit after_success: diff --git a/README.md b/README.md index bd2bb85..e464aca 100644 --- a/README.md +++ b/README.md @@ -25,15 +25,34 @@ Google Group for discussions, support, advice etc: [http://groups.google.co.uk/g ## Integration tests +### Memory + + * `npm run test:integration` (default) + * `npm run test:integration:memory` + +### Redis + + * `redis-server` (don't forget to start redis server) + * `npm run test:integration:redis` + +### InterSystem Caché + * You must have [InterSystem Caché](http://www.intersystems.com/our-products/cache/cache-overview/) installed * You must have `cache.node` in npm global registy. Read [Installation](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=BXJS_intro#BXJS_intro_install) to get more details * Run `npm link cache.node` before running integration tests * You may need to run this as sudo because of permissions + * Run `npm run test:integration:cache` + +### Gtm or YottaDb + * `cd ./docker/gtm` + * `docker build -t .` + * `docker run -it --rm -v ~/path/to/ewd-document-store:/opt/qewd/mapped /bin/bash` + * `cd mapped && npm run test:integration:gtm` ## License - Copyright (c) 2013-17 M/Gateway Developments Ltd, + Copyright (c) 2013-19 M/Gateway Developments Ltd, Reigate, Surrey UK. All rights reserved. diff --git a/docker/gtm/.dockerignore b/docker/gtm/.dockerignore new file mode 100644 index 0000000..e0ba315 --- /dev/null +++ b/docker/gtm/.dockerignore @@ -0,0 +1,2 @@ +.git +node_modules \ No newline at end of file diff --git a/docker/gtm/Dockerfile b/docker/gtm/Dockerfile new file mode 100644 index 0000000..7e4971b --- /dev/null +++ b/docker/gtm/Dockerfile @@ -0,0 +1,6 @@ +FROM rtweed/qewd-server + +COPY ./entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh", "-l"] \ No newline at end of file diff --git a/docker/gtm/entrypoint.sh b/docker/gtm/entrypoint.sh new file mode 100755 index 0000000..37f7c6b --- /dev/null +++ b/docker/gtm/entrypoint.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +export gtm_version=V6.3-004 +export ydb_versionp=r1.24 +export ydb_version=r124 +export ydb_arch=x86_64 + +export ydb_path="${ydb_versionp}_${ydb_arch}" +export gtm_path="${gtm_version}_${ydb_arch}" + +export ydb_retention=42 +export gtm_retention=42 +export LD_LIBRARY_PATH="/usr/local/lib/yottadb/${ydb_version}" +export ydb_log="/tmp/yottadb/${ydb_path}" +export gtm_log="/tmp/yottadb/${ydb_path}" +export gtm_repl_instance="/root/.yottadb/${ydb_path}/g/yottadb.repl" +export ydb_repl_instance="/root/.yottadb/${ydb_path}/g/yottadb.repl" +export ydb_gbldir="/root/.yottadb/${ydb_path}/g/yottadb.gld" +export ydb_etrap='Write:(0=$STACK) "Error occurred=",$ZStatus,!' +export ydb_dir="/root/.yottadb" +export gtmver=$gtm_path +export ydb_rel=$ydb_path +export gtmgbldir="/root/.yottadb/${ydb_path}/g/yottadb.gld" +export ydb_routines="/opt/qewd/node_modules/nodem/src /root/.yottadb/${ydb_path}/o*(/root/.yottadb/${ydb_path}/r /root/.yottadb/r) /usr/local/lib/yottadb/${ydb_version}/libyottadbutil.so" +export gtmroutines="/opt/qewd/node_modules/nodem/src /root/.yottadb/${ydb_path}/o*(/root/.yottadb/${ydb_path}/r /root/.yottadb/r) /usr/local/lib/yottadb/${ydb_version}/libyottadbutil.so" +export GTMCI="/opt/qewd/node_modules/nodem/resources/nodem.ci" +export ydb_ci="/opt/qewd/node_modules/nodem/resources/nodem.ci" +export gtmdir=/root/.fis-gtm +export gtm_etrap='Write:(0=$STACK) "Error occurred=",$ZStatus,!' +export ydb_tmp="/tmp/yottadb/${ydb_path}" +export gtm_tmp="/tmp/yottadb/${ydb_path}" +export gtm_dist="/usr/local/lib/yottadb/${ydb_version}" +export ydb_dist="/usr/local/lib/yottadb/${ydb_version}" + +exec "$@" \ No newline at end of file diff --git a/lib/proto/forEach.js b/lib/proto/forEach.js index dc161b2..ac82ea4 100644 --- a/lib/proto/forEach.js +++ b/lib/proto/forEach.js @@ -102,6 +102,9 @@ module.exports = function(callback) { node = {global: this.documentName, subscripts: subs}; if (direction === 'forwards') { seed = db.previous(node).result; + subs = this.path.slice(0); + subs.push(seed); + node = {global: this.documentName, subscripts: subs}; } } } diff --git a/lib/proto/forEachLeafNode.js b/lib/proto/forEachLeafNode.js index f0cded6..4f6f5ca 100644 --- a/lib/proto/forEachLeafNode.js +++ b/lib/proto/forEachLeafNode.js @@ -25,7 +25,7 @@ | limitations under the License. | ---------------------------------------------------------------------------- - 7 September 2017 + 9 October 2018 */ diff --git a/lib/proto/getDocument.js b/lib/proto/getDocument.js index 48b6fed..5e68572 100644 --- a/lib/proto/getDocument.js +++ b/lib/proto/getDocument.js @@ -28,18 +28,6 @@ 21 January 2019 */ -/* - - No longer needed - GT.M bug fixed - -function removeDoubleQuotes(value, db) { - if (db.version().indexOf('GT.M') !== -1 && value.toString().indexOf('""') !== -1) { - value = value.split('""').join('"'); - } - return value; -} -*/ - const NON_EXISTENT = 0; const LEAF_NODE = 1; const NO_DATA_HAS_CHILDREN = 10; @@ -104,12 +92,8 @@ module.exports = function(useArrays, offset) { index = result; if (isArray) index = index - offset; defined = db.data(node).defined; - //if (defined === LEAF_NODE) { if (defined === LEAF_NODE || defined === HAS_DATA_HAS_CHILDREN) { document[index] = convert(db.get(node).data); - //if (document[index] === 'true') document[index] = true; - //if (document[index] === 'false') document[index] = false; - //document[index] = removeDoubleQuotes(document[index], db); } if (defined === NO_DATA_HAS_CHILDREN || defined === HAS_DATA_HAS_CHILDREN) { document[index] = getSubnodes(node); @@ -170,12 +154,7 @@ module.exports = function(useArrays, offset) { do { delete node.data; node = db.next_node(node); - //data = node.data || ''; data = convert(node.data); - //if (typeof data === 'undefined') data = ''; - //if (data === 'false') data = false; - //if (data === 'true') data = true; - //data = removeDoubleQuotes(data, db); match = false; if (node.defined !== NON_EXISTENT) match = isSubNode(signature, node.subscripts); if (match) { diff --git a/lib/proto/increment.js b/lib/proto/increment.js index 8dab012..b625e2a 100644 --- a/lib/proto/increment.js +++ b/lib/proto/increment.js @@ -42,7 +42,7 @@ module.exports = function() { }; var node = this._node; var value = documentStore.db.increment(node).data; - value = parseInt(value); + value = parseInt(value, 10); enode.value = value; documentStore.emit('afterSet', enode); return value; diff --git a/lib/proto/setDocument.js b/lib/proto/setDocument.js index 04bc317..ca99adf 100644 --- a/lib/proto/setDocument.js +++ b/lib/proto/setDocument.js @@ -25,24 +25,29 @@ | limitations under the License. | ---------------------------------------------------------------------------- - 7 September 2017 + 9 October 2018 */ module.exports = function(document, offset) { - var set = this._set; var that = this; var documentName = this.documentName; if (!offset) offset = 0; + var set = function(value, node) { + that._set.call(that, value, node); + }; + var setFast = function(obj, documentNode) { var subs; var i; var j; var node; var value; + for (i in obj){ if (obj[i] === null || typeof obj[i] === 'undefined') obj[i] = ''; + if (obj[i] instanceof Array) { //console.log('Array! ' + JSON.stringify(obj[i])); if (obj[i].length !== 0) { @@ -52,7 +57,7 @@ module.exports = function(document, offset) { subs.push(i); subs.push(j + offset); setFast(obj[i][j], {global: documentName, path: subs}); - } + } else { value = obj[i][j]; if (value === null) value = ''; @@ -60,19 +65,21 @@ module.exports = function(document, offset) { subs.push(i); subs.push(j + offset); node = {global: documentName, subscripts: subs}; - set.call(that, value, node); + set(value, node); } } } } + if (typeof obj[i] !== 'object') { value = obj[i]; if (value === null || typeof value === 'undefined') value = ''; subs = documentNode.path.slice(0); subs.push(i); node = {global: documentName, subscripts: subs}; - set.call(that, value, node); - } + set(value, node); + } + if (obj[i] instanceof Object && !(obj[i] instanceof Array)) { subs = documentNode.path.slice(0); subs.push(i); diff --git a/package.json b/package.json index 63fb695..c7c76b6 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,7 @@ "url": "https://github.com/robtweed/ewd-document-store/issues" }, "engines": { - "node": ">= 0.10", - "npm": ">= 2.15" + "node": ">= 4" }, "repository": { "type": "git", @@ -25,10 +24,15 @@ "test": "npm run test:unit && npm run test:integration", "test:unit": "jasmine --config=spec/support/unit.json", "test:integration": "jasmine --config=spec/support/integration.json", + "test:integration:gtm": "DATABASE=gtm jasmine --config=spec/support/integration.json", + "test:integration:cache": "DATABASE=cache jasmine --config=spec/support/integration.json", + "test:integration:redis": "DATABASE=redis jasmine --config=spec/support/integration.json", "coverage:unit": "nyc --reporter=html --reporter=text jasmine --config=spec/support/unit.json", - "coverage:integration": "nyc --reporter=html --reporter=text jasmine --config=spec/support/integration.json", - "coveralls": "nyc report --reporter=text-lcov | coveralls", - "validate": "npm ls" + "coverage:integration": "nyc --reporter=html --reporter=text npm run test:integration", + "coverage:integration:gtm": "nyc --reporter=html --reporter=text npm run test:integration:gtm", + "coverage:integration:cache": "nyc --reporter=html --reporter=text npm run test:integration:cache", + "coverage:integration:redis": "nyc --reporter=html --reporter=text npm run test:integration:redis", + "coveralls": "nyc report --reporter=text-lcov | coveralls" }, "pre-commit": [ "lint", @@ -38,19 +42,20 @@ "all": true, "include": [ "lib/**/*.js" - ], - "exclude": [ - "spec/**/*.js" ] }, "devDependencies": { - "coveralls": "^2.13.1", - "dotenv": "^4.0.0", - "jasmine": "^2.8.0", + "coveralls": "^3.0.2", + "dotenv": "^6.1.0", + "ewd-memory-globals": "^1.0.3", + "ewd-redis-globals": "^0.5.0", + "jasmine": "^3.2.0", "jasmine-spec-reporter": "^4.1.1", - "jshint": "^2.9.5", - "nyc": "^11.1.0", + "jasmine-spy-matchers": "^2.1.0", + "jshint": "^2.9.6", + "nyc": "^13.0.1", "pre-commit": "^1.2.2", - "rewire": "^2.5.2" + "rewire": "^4.0.1", + "tcp-netx": "^1.0.7-a" } } diff --git a/spec/helpers/matchers.js b/spec/helpers/matchers.js new file mode 100644 index 0000000..9b7e1cc --- /dev/null +++ b/spec/helpers/matchers.js @@ -0,0 +1 @@ +require('jasmine-spy-matchers'); diff --git a/spec/integration/dbFactory.js b/spec/integration/dbFactory.js new file mode 100644 index 0000000..d98286c --- /dev/null +++ b/spec/integration/dbFactory.js @@ -0,0 +1,81 @@ +'use strict'; + +function initCacheDb() { + var Cache = require('cache').Cache; + var db = new Cache(); + + var openFn = db.open; + var options = { + path: process.env.CACHE_MGR_PATH || '/opt/cache/mgr', + username: process.env.CACHE_USERNAME || '_SYSTEM', + password: process.env.CACHE_PASSWORD || 'SYS', + namespace: process.env.CACHE_NAMESPACE || 'USER' + }; + + db.open = function () { + openFn.call(db, options); + }; + + return db; +} + +function initGtmDb() { + var Gtm = require('nodem').Gtm; + var db = new Gtm(); + + + var openFn = db.open; + var options = { + mode: 'strict', + charset: 'utf-8' + }; + + db.open = function () { + openFn.call(db, options); + }; + + return db; +} + +function initRedisDb() { + /*jshint camelcase: false */ + var Redis = require('ewd-redis-globals'); + var db = new Redis({ + key_separator: ':', + integer_padding: 10 + }); + /*jshint camelcase: true */ + + return db; +} + +function initMemoryDb() { + /*jshint camelcase: false */ + var Memory = require('ewd-memory-globals'); + var db = new Memory({ + key_separator: ':', + integer_padding: 10 + }); + /*jshint camelcase: true */ + + return db; +} + +module.exports = function () { + switch (process.env.DATABASE) { + case 'cache': + return initCacheDb(); + + case 'gtm': + return initGtmDb(); + + case 'redis': + return initRedisDb(); + + case 'memory': + return initMemoryDb(); + + default: + return initMemoryDb(); + } +}; diff --git a/spec/integration/ewd-document-store.spec.js b/spec/integration/ewd-document-store.spec.js index d3db309..e644d70 100644 --- a/spec/integration/ewd-document-store.spec.js +++ b/spec/integration/ewd-document-store.spec.js @@ -2,23 +2,18 @@ require('dotenv').config(); +var dbFactory = require('./dbFactory'); var DocumentStore = require('../../'); -var Cache = require('cache').Cache; -describe(' - integration/ewd-document-store: ', function () { +describe('integration/ewd-document-store:', function () { var db; var documentStore; beforeAll(function () { - db = new Cache(); + db = dbFactory(); documentStore = new DocumentStore(db); - db.open({ - path: process.env.CACHE_MGR_PATH || '/opt/cache/mgr', - username: process.env.CACHE_USERNAME || '_SYSTEM', - password: process.env.CACHE_PASSWORD || 'SYS', - namespace: process.env.CACHE_NAMESPACE || 'USER' - }); + db.open(); }); afterAll(function () { @@ -164,7 +159,7 @@ describe(' - integration/ewd-document-store: ', function () { foo.increment(); - expect(foo.value).toBe('1'); + expect(foo.value).toBe(1); }); it('#countChildren', function () { @@ -254,6 +249,27 @@ describe(' - integration/ewd-document-store: ', function () { expect(actual).toEqual(expected); }); + it('should return all children in reverse direction #2', function () { + var expected = [ + ['d', 'temp', 'foo', 'd'], + ['c', 'temp', 'foo', 'c'], + ['b', 'temp', 'foo', 'b'], + ['a', 'temp', 'foo', 'a'], + ['Douglas', 'temp', 'foo', 'Douglas'], + ['Davis', 'temp', 'foo', 'Davis'], + ['Davies', 'temp', 'foo', 'Davies'], + ['Briggs', 'temp', 'foo', 'Briggs'], + ['Barton', 'temp', 'foo', 'Barton'] + ]; + + var actual = []; + documentNode.$('foo').forEachChild('reverse', function (nodeName, node) { + actual.push([nodeName, node.documentName].concat(node.path)); + }); + + expect(actual).toEqual(expected); + }); + it('should return children using prefix', function () { var expected = [ ['Barton', 'temp', 'foo', 'Barton'], @@ -292,7 +308,7 @@ describe(' - integration/ewd-document-store: ', function () { expect(actual).toEqual(expected); }); - it('should return from-to range (boundaries)', function () { + it('should return from-to range (boundaries, forwards)', function () { var expected = [ ['Briggs', 'temp', 'foo', 'Briggs'], ['Davies', 'temp', 'foo', 'Davies'], @@ -312,7 +328,7 @@ describe(' - integration/ewd-document-store: ', function () { expect(actual).toEqual(expected); }); - it('should return from-* range', function () { + it('should return from-* range (forwards)', function () { var expected = [ ['Davies', 'temp', 'foo', 'Davies'], ['Davis', 'temp', 'foo', 'Davis'], @@ -335,6 +351,28 @@ describe(' - integration/ewd-document-store: ', function () { expect(actual).toEqual(expected); }); + it('should return from-* range (reverse)', function () { + var expected = [ + ['Douglas', 'temp', 'foo', 'Douglas'], + ['Davis', 'temp', 'foo', 'Davis'], + ['Davies', 'temp', 'foo', 'Davies'], + ['Briggs', 'temp', 'foo', 'Briggs'], + ['Barton', 'temp', 'foo', 'Barton'] + ]; + + var actual = []; + documentNode.$('foo').forEachChild({ + direction: 'reverse', + range: { + from: 'D' + } + }, function (nodeName, node) { + actual.push([nodeName, node.documentName].concat(node.path)); + }); + + expect(actual).toEqual(expected); + }); + it('should return *-to range', function () { var expected = [ ['Barton', 'temp', 'foo', 'Barton'], @@ -355,6 +393,30 @@ describe(' - integration/ewd-document-store: ', function () { expect(actual).toEqual(expected); }); + + it('should return *-to range (reverse)', function () { + var expected = [ + ['d', 'temp', 'foo', 'd'], + ['c', 'temp', 'foo', 'c'], + ['b', 'temp', 'foo', 'b'], + ['a', 'temp', 'foo', 'a'], + ['Douglas', 'temp', 'foo', 'Douglas'], + ['Davis', 'temp', 'foo', 'Davis'], + ['Davies', 'temp', 'foo', 'Davies'] + ]; + + var actual = []; + documentNode.$('foo').forEachChild({ + direction: 'reverse', + range: { + to: 'D' + } + }, function (nodeName, node) { + actual.push([nodeName, node.documentName].concat(node.path)); + }); + + expect(actual).toEqual(expected); + }); }); describe('#forEachLeafNode', function () { @@ -484,7 +546,7 @@ describe(' - integration/ewd-document-store: ', function () { expect(actual).toEqual(expected); }); - it('should return document with arrays and offset', function () { + it('should return document with arrays and offset (array)', function () { var expected = { c: ['a', 's', 'd'] }; @@ -503,6 +565,50 @@ describe(' - integration/ewd-document-store: ', function () { expect(actual).toEqual(expected); }); + + it('should return document with arrays and offset (object with keys)', function () { + var expected = { + c: ['a', 's', 'd'] + }; + + var useArrays = true; + var offset = 1; + + var foo = { + c: { + '1': 'a', + '2': 's', + '3': 'd', + } + }; + + documentNode.$('foo').delete(); + documentNode.$('foo').setDocument(foo, offset); + + var actual = documentNode.$('foo').getDocument(useArrays, offset); + + expect(actual).toEqual(expected); + }); + + // memory and redis providers needs to support it + if (process.env.DATABASE === 'gtm') { + it('should return document with utf-8 characters', function () { + var expected = { + baz: 'Thắng Nguyễn' + }; + + var foo = { + baz: 'Thắng Nguyễn' + }; + + documentNode.$('foo').delete(); + documentNode.$('foo').setDocument(foo); + + var actual = documentNode.$('foo').getDocument(); + + expect(actual).toEqual(expected); + }); + } }); describe('#setDocument', function () { @@ -614,7 +720,6 @@ describe(' - integration/ewd-document-store: ', function () { }); var actual = documentStore.list(); - expect(actual).toEqual(expected); ['foo', 'bar', 'baz'].forEach(function (name) { diff --git a/spec/unit/documentStore.spec.js b/spec/unit/documentStore.spec.js index d4d122e..38734cc 100644 --- a/spec/unit/documentStore.spec.js +++ b/spec/unit/documentStore.spec.js @@ -4,7 +4,7 @@ var events = require('events'); var rewire = require('rewire'); var DocumentStore = rewire('../../lib/documentStore'); -describe(' - unit/documentStore:', function () { +describe('unit/documentStore:', function () { var revertBuild; beforeEach(function () { @@ -132,6 +132,8 @@ describe(' - unit/documentStore:', function () { 'getDocument', 'setDocument', 'forEachLeafNode', + 'lock', + 'unlock', '_set' ].forEach(function (method) { describe('#' + method, function () { diff --git a/spec/unit/mocks/db.js b/spec/unit/mocks/db.js index 4b11928..4b0bf80 100644 --- a/spec/unit/mocks/db.js +++ b/spec/unit/mocks/db.js @@ -12,6 +12,8 @@ module.exports = { get: jasmine.createSpy(), set: jasmine.createSpy(), version: jasmine.createSpy(), + lock: jasmine.createSpy(), + unlock: jasmine.createSpy(), /*jshint camelcase: false */ global_directory: jasmine.createSpy(), diff --git a/spec/unit/proto/convert.spec.js b/spec/unit/proto/convert.spec.js new file mode 100644 index 0000000..4f7379f --- /dev/null +++ b/spec/unit/proto/convert.spec.js @@ -0,0 +1,54 @@ +'use strict'; + +var convert = require('../../../lib/proto/convert'); + +describe('unit/proto/convert:', function () { + it('should return empty string when undefined type', function () { + var actual = convert(undefined); + + expect(actual).toBe(''); + }); + + it('should return true when "true"', function () { + var actual = convert('true'); + + expect(actual).toBe(true); + }); + + it('should return false when "false"', function () { + var actual = convert('false'); + + expect(actual).toBe(false); + }); + + it('should return float number', function () { + var actual = convert('0.014'); + + expect(actual).toBe(0.014); + }); + + it('should return int number', function () { + var actual = convert('136'); + + expect(actual).toBe(136); + }); + + it('should return float number', function () { + var actual = convert('13.6'); + + expect(actual).toBe(13.6); + }); + + it('should return string', function () { + var actual = convert('foo'); + + expect(actual).toBe('foo'); + }); + + // https://github.com/robtweed/ewd-document-store/issues/23 + it('should return string', function () { + var actual = convert('0.foo'); + + expect(actual).toBe('0.foo'); + }); +}); diff --git a/spec/unit/proto/count.spec.js b/spec/unit/proto/count.spec.js index d7e514b..ec08da6 100644 --- a/spec/unit/proto/count.spec.js +++ b/spec/unit/proto/count.spec.js @@ -3,7 +3,7 @@ var count = require('../../../lib/proto/count'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/count:', function () { +describe('unit/proto/count:', function () { var DocumentStore; var documentStore; var DocumentNode; diff --git a/spec/unit/proto/defined.spec.js b/spec/unit/proto/defined.spec.js index 003c25e..13e9e0b 100644 --- a/spec/unit/proto/defined.spec.js +++ b/spec/unit/proto/defined.spec.js @@ -3,7 +3,7 @@ var defined = require('../../../lib/proto/defined'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/defined:', function () { +describe('unit/proto/defined:', function () { var DocumentStore; var documentStore; var DocumentNode; diff --git a/spec/unit/proto/delete.spec.js b/spec/unit/proto/delete.spec.js index c7a62f8..b39d4d0 100644 --- a/spec/unit/proto/delete.spec.js +++ b/spec/unit/proto/delete.spec.js @@ -3,7 +3,7 @@ var deleteMethod = require('../../../lib/proto/delete'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/delete:', function () { +describe('unit/proto/delete:', function () { var DocumentStore; var documentStore; var DocumentNode; diff --git a/spec/unit/proto/dollar.spec.js b/spec/unit/proto/dollar.spec.js index 91632bb..683ab7f 100644 --- a/spec/unit/proto/dollar.spec.js +++ b/spec/unit/proto/dollar.spec.js @@ -3,7 +3,7 @@ var $ = require('../../../lib/proto/dollar'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/dollar:', function () { +describe('unit/proto/dollar:', function () { var DocumentStore; var documentStore; var DocumentNode; diff --git a/spec/unit/proto/exists.spec.js b/spec/unit/proto/exists.spec.js index 27a186d..6aa0093 100644 --- a/spec/unit/proto/exists.spec.js +++ b/spec/unit/proto/exists.spec.js @@ -3,7 +3,7 @@ var exists = require('../../../lib/proto/exists'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/exists:', function () { +describe('unit/proto/exists:', function () { var DocumentStore; var documentStore; var DocumentNode; diff --git a/spec/unit/proto/firstChild.spec.js b/spec/unit/proto/firstChild.spec.js index 37e237d..441fd33 100644 --- a/spec/unit/proto/firstChild.spec.js +++ b/spec/unit/proto/firstChild.spec.js @@ -3,7 +3,7 @@ var firstChild = require('../../../lib/proto/firstChild'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/firstChild:', function () { +describe('unit/proto/firstChild:', function () { var DocumentStore; var documentStore; var DocumentNode; diff --git a/spec/unit/proto/forEach.spec.js b/spec/unit/proto/forEach.spec.js index 447385e..6c71e82 100644 --- a/spec/unit/proto/forEach.spec.js +++ b/spec/unit/proto/forEach.spec.js @@ -4,7 +4,7 @@ var forEach = require('../../../lib/proto/forEach'); var dbMock = require('../mocks/db'); var FIELD_MARK = String.fromCharCode(254); -describe(' - unit/proto/forEach:', function () { +describe('unit/proto/forEach:', function () { var DocumentStore; var documentStore; var DocumentNode; @@ -100,12 +100,22 @@ describe(' - unit/proto/forEach:', function () { })); }); - it('should call callback exact times with correct arguments', function () { + it('should call callback exact times with correct arguments and context', function () { documentNode.forEachChild(callback); expect(callback).toHaveBeenCalledTimes(2); - expect(callback.calls.argsFor(0)).toEqual(['fooValue', jasmine.any(DocumentNode)]); - expect(callback.calls.argsFor(1)).toEqual(['barValue', jasmine.any(DocumentNode)]); + expect(callback.calls.all()[0]).toEqual( + jasmine.objectContaining({ + object: documentNode, + args: ['fooValue', jasmine.any(DocumentNode)] + }) + ); + expect(callback.calls.all()[1]).toEqual( + jasmine.objectContaining({ + object: documentNode, + args: ['barValue', jasmine.any(DocumentNode)] + }) + ); }); it('should quit from loop', function () { diff --git a/spec/unit/proto/forEachLeafNode.spec.js b/spec/unit/proto/forEachLeafNode.spec.js index b8300c1..e18569c 100644 --- a/spec/unit/proto/forEachLeafNode.spec.js +++ b/spec/unit/proto/forEachLeafNode.spec.js @@ -3,7 +3,7 @@ var forEachLeafNode = require('../../../lib/proto/forEachLeafNode'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/forEachLeafNode:', function () { +describe('unit/proto/forEachLeafNode:', function () { var DocumentStore; var documentStore; var DocumentNode; @@ -78,19 +78,21 @@ describe(' - unit/proto/forEachLeafNode:', function () { /*jshint camelcase: true */ }); - it('should call callback exact times with correct arguments', function () { + it('should call callback exact times with correct arguments and context', function () { documentNode.forEachLeafNode(callback); expect(callback).toHaveBeenCalledTimes(2); - expect(callback.calls.argsFor(0)).toEqual(['barValue', jasmine.any(DocumentNode)]); - expect(callback.calls.argsFor(0)[1]).toEqual(jasmine.objectContaining({ + expect(callback.calls.thisArgFor(0)).toBe(documentNode); + expect(callback.calls.at(0).args).toEqual(['barValue', jasmine.any(DocumentNode)]); + expect(callback.calls.at(0).args[1]).toEqual(jasmine.objectContaining({ documentName: 'rob', path: ['foo', 'bar'] })); - expect(callback.calls.argsFor(1)).toEqual(['bazValue', jasmine.any(DocumentNode)]); - expect(callback.calls.argsFor(1)[1]).toEqual(jasmine.objectContaining({ + expect(callback.calls.thisArgFor(1)).toBe(documentNode); + expect(callback.calls.at(1).args).toEqual(['bazValue', jasmine.any(DocumentNode)]); + expect(callback.calls.at(1).args[1]).toEqual(jasmine.objectContaining({ documentName: 'rob', path: ['foo', 'baz'] })); @@ -102,7 +104,7 @@ describe(' - unit/proto/forEachLeafNode:', function () { documentNode.forEachLeafNode(callback); expect(callback).toHaveBeenCalledTimes(1); - expect(callback).toHaveBeenCalledWith('barValue', jasmine.any(DocumentNode)); + expect(callback).toHaveBeenCalledWithContext(documentNode, 'barValue', jasmine.any(DocumentNode)); }); it('should process when not within root', function () { @@ -142,6 +144,6 @@ describe(' - unit/proto/forEachLeafNode:', function () { documentNode.forEachLeafNode(callback); expect(callback).toHaveBeenCalledTimes(1); - expect(callback).toHaveBeenCalledWith('', jasmine.any(DocumentNode)); + expect(callback).toHaveBeenCalledWithContext(documentNode, '', jasmine.any(DocumentNode)); }); }); diff --git a/spec/unit/proto/getDocument.spec.js b/spec/unit/proto/getDocument.spec.js index f52b4d7..b0115de 100644 --- a/spec/unit/proto/getDocument.spec.js +++ b/spec/unit/proto/getDocument.spec.js @@ -3,7 +3,7 @@ var getDocument = require('../../../lib/proto/getDocument'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/setDocument:', function () { +describe('unit/proto/getDocument:', function () { var DocumentStore; var documentStore; var DocumentNode; @@ -38,12 +38,28 @@ describe(' - unit/proto/setDocument:', function () { db.version.and.returnValue('Node.js Adaptor for Cache: Version: 1.1.112 (CM); Cache Version: 2016.3 build 168'); db.data.and.returnValue( { + ok: 1, defined: 1 } ); }); - it('should return empty object', function () { + it('should return empty object when non ok', function () { + var expected = {}; + + db.data.and.returnValue({ + ok: 0 + }); + + var actual = documentNode.getDocument(); + + expect(actual).toEqual(expected); + expect(db.data).toHaveBeenCalledWith({ + global: 'rob' + }); + }); + + it('should return empty object when non defined', function () { var expected = {}; db.data.and.returnValue({ @@ -105,7 +121,6 @@ describe(' - unit/proto/setDocument:', function () { }) ); /*jshint camelcase: true */ - }); it('should process node contains bool data', function () { @@ -200,6 +215,7 @@ describe(' - unit/proto/setDocument:', function () { db.data.and.returnValues( { + ok: 1, defined: 1 }, { @@ -273,6 +289,7 @@ describe(' - unit/proto/setDocument:', function () { db.data.and.returnValues( { + ok: 1, defined: 1 }, { @@ -328,6 +345,7 @@ describe(' - unit/proto/setDocument:', function () { db.data.and.returnValues( { + ok: 1, defined: 1 }, { @@ -384,6 +402,7 @@ describe(' - unit/proto/setDocument:', function () { db.data.and.returnValues( { + ok: 1, defined: 1 }, { @@ -500,6 +519,7 @@ describe(' - unit/proto/setDocument:', function () { db.data.and.returnValues( { + ok: 1, defined: 1 }, { @@ -606,6 +626,7 @@ describe(' - unit/proto/setDocument:', function () { db.data.and.returnValues( { + ok: 1, defined: 1 }, { @@ -709,6 +730,7 @@ describe(' - unit/proto/setDocument:', function () { db.data.and.returnValues( { + ok: 1, defined: 1 }, { @@ -758,5 +780,4 @@ describe(' - unit/proto/setDocument:', function () { expect(actual).toEqual(expected); }); }); - }); diff --git a/spec/unit/proto/hasChildren.spec.js b/spec/unit/proto/hasChildren.spec.js index d0decd2..7e0e278 100644 --- a/spec/unit/proto/hasChildren.spec.js +++ b/spec/unit/proto/hasChildren.spec.js @@ -3,7 +3,7 @@ var hasChildren = require('../../../lib/proto/hasChildren'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/hasChildren:', function () { +describe('unit/proto/hasChildren:', function () { var DocumentStore; var documentStore; var DocumentNode; diff --git a/spec/unit/proto/hasValue.spec.js b/spec/unit/proto/hasValue.spec.js index a8c0722..c23f3da 100644 --- a/spec/unit/proto/hasValue.spec.js +++ b/spec/unit/proto/hasValue.spec.js @@ -3,7 +3,7 @@ var hasValue = require('../../../lib/proto/hasValue'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/hasValue:', function () { +describe('unit/proto/hasValue:', function () { var DocumentStore; var documentStore; var DocumentNode; diff --git a/spec/unit/proto/increment.spec.js b/spec/unit/proto/increment.spec.js index 0f624e8..1c4485a 100644 --- a/spec/unit/proto/increment.spec.js +++ b/spec/unit/proto/increment.spec.js @@ -3,7 +3,7 @@ var increment = require('../../../lib/proto/increment'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/increment:', function () { +describe('unit/proto/increment:', function () { var DocumentStore; var documentStore; var DocumentNode; diff --git a/spec/unit/proto/lastChild.spec.js b/spec/unit/proto/lastChild.spec.js index 6a28f22..4df121a 100644 --- a/spec/unit/proto/lastChild.spec.js +++ b/spec/unit/proto/lastChild.spec.js @@ -3,7 +3,7 @@ var lastChild = require('../../../lib/proto/lastChild'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/lastChild:', function () { +describe('unit/proto/lastChild:', function () { var DocumentStore; var documentStore; var DocumentNode; diff --git a/spec/unit/proto/list.spec.js b/spec/unit/proto/list.spec.js index 76d6fde..7b1ef23 100644 --- a/spec/unit/proto/list.spec.js +++ b/spec/unit/proto/list.spec.js @@ -3,7 +3,7 @@ var list = require('../../../lib/proto/list'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/list:', function () { +describe('unit/proto/list:', function () { var DocumentStore; var documentStore; var db; diff --git a/spec/unit/proto/lock.spec.js b/spec/unit/proto/lock.spec.js new file mode 100644 index 0000000..f7ce477 --- /dev/null +++ b/spec/unit/proto/lock.spec.js @@ -0,0 +1,65 @@ +'use strict'; + +var lock = require('../../../lib/proto/lock'); +var dbMock = require('../mocks/db'); + +describe('unit/proto/lock:', function () { + var DocumentStore; + var documentStore; + var DocumentNode; + var documentNode; + var db; + + beforeAll(function () { + DocumentNode = function (documentStore) { + this.documentStore = documentStore; + + this.documentName = 'rob'; + this.path = ['foo']; + this._node = { + global: 'rob', + subscripts: ['foo'] + }; + + this.lock = lock; + }; + + DocumentStore = function (db) { + this.db = db; + this.emit = jasmine.createSpy(); + this.DocumentNode = DocumentNode.bind(undefined, this); + }; + }); + + beforeEach(function () { + db = dbMock.mock(); + documentStore = new DocumentStore(db); + documentNode = new documentStore.DocumentNode(); + }); + + it('should return true', function () { + documentStore.db.lock.and.returnValue({result: '1'}); + + var actual = documentNode.lock(600); + + expect(actual).toBeTruthy(); + + expect(documentStore.db.lock).toHaveBeenCalledWith({ + global: 'rob', + subscripts: ['foo'] + }, 600); + }); + + it('should return false', function () { + documentStore.db.lock.and.returnValue({result: ''}); + + var actual = documentNode.lock(600); + + expect(actual).toBeFalsy(); + + expect(documentStore.db.lock).toHaveBeenCalledWith({ + global: 'rob', + subscripts: ['foo'] + }, 600); + }); +}); diff --git a/spec/unit/proto/nextSibling.spec.js b/spec/unit/proto/nextSibling.spec.js index 0e3a9fc..1cab1d2 100644 --- a/spec/unit/proto/nextSibling.spec.js +++ b/spec/unit/proto/nextSibling.spec.js @@ -3,7 +3,7 @@ var nextSibling = require('../../../lib/proto/nextSibling'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/nextSibling:', function () { +describe('unit/proto/nextSibling:', function () { var DocumentStore; var documentStore; var DocumentNode; diff --git a/spec/unit/proto/parent.spec.js b/spec/unit/proto/parent.spec.js index b221145..97dbb53 100644 --- a/spec/unit/proto/parent.spec.js +++ b/spec/unit/proto/parent.spec.js @@ -3,7 +3,7 @@ var parent = require('../../../lib/proto/parent'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/parent:', function () { +describe('unit/proto/parent:', function () { var DocumentStore; var documentStore; var DocumentNode; diff --git a/spec/unit/proto/previousSibling.spec.js b/spec/unit/proto/previousSibling.spec.js index 593bf49..202428e 100644 --- a/spec/unit/proto/previousSibling.spec.js +++ b/spec/unit/proto/previousSibling.spec.js @@ -3,7 +3,7 @@ var previousSibling = require('../../../lib/proto/previousSibling'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/previousSibling:', function () { +describe('unit/proto/previousSibling:', function () { var DocumentStore; var documentStore; var DocumentNode; diff --git a/spec/unit/proto/set.spec.js b/spec/unit/proto/set.spec.js index 4ae3984..2e08548 100644 --- a/spec/unit/proto/set.spec.js +++ b/spec/unit/proto/set.spec.js @@ -3,7 +3,7 @@ var set = require('../../../lib/proto/set'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/set:', function () { +describe('unit/proto/set:', function () { var DocumentStore; var documentStore; var DocumentNode; diff --git a/spec/unit/proto/setDocument.spec.js b/spec/unit/proto/setDocument.spec.js index 89d38e0..070a763 100644 --- a/spec/unit/proto/setDocument.spec.js +++ b/spec/unit/proto/setDocument.spec.js @@ -3,7 +3,7 @@ var setDocument = require('../../../lib/proto/setDocument'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/setDocument:', function () { +describe('unit/proto/setDocument:', function () { var DocumentStore; var documentStore; var DocumentNode; @@ -45,7 +45,7 @@ describe(' - unit/proto/setDocument:', function () { documentNode.setDocument(obj); - expect(documentNode._set).toHaveBeenCalledWith('', { + expect(documentNode._set).toHaveBeenCalledWithContext(documentNode, '', { global: 'rob', subscripts: ['address', 'bar'] }); @@ -58,7 +58,7 @@ describe(' - unit/proto/setDocument:', function () { documentNode.setDocument(obj); - expect(documentNode._set).toHaveBeenCalledWith('', { + expect(documentNode._set).toHaveBeenCalledWithContext(documentNode, '', { global: 'rob', subscripts: ['address', 'bar'] }); @@ -71,7 +71,7 @@ describe(' - unit/proto/setDocument:', function () { documentNode.setDocument(obj); - expect(documentNode._set).toHaveBeenCalledWith('baz', { + expect(documentNode._set).toHaveBeenCalledWithContext(documentNode, 'baz', { global: 'rob', subscripts: ['address', 'bar'] }); @@ -84,7 +84,7 @@ describe(' - unit/proto/setDocument:', function () { documentNode.setDocument(obj); - expect(documentNode._set).toHaveBeenCalledWith(10, { + expect(documentNode._set).toHaveBeenCalledWithContext(documentNode, 10, { global: 'rob', subscripts: ['address', 'bar'] }); @@ -108,14 +108,30 @@ describe(' - unit/proto/setDocument:', function () { documentNode.setDocument(obj); expect(documentNode._set).toHaveBeenCalledTimes(2); - expect(documentNode._set.calls.argsFor(0)).toEqual(['a', { - global: 'rob', - subscripts: ['address', 'bar', 0] - }]); - expect(documentNode._set.calls.argsFor(1)).toEqual(['b', { - global: 'rob', - subscripts: ['address', 'bar', 1] - }]); + expect(documentNode._set.calls.all()[0]).toEqual( + jasmine.objectContaining({ + object: documentNode, + args: [ + 'a', + { + global: 'rob', + subscripts: ['address', 'bar', 0] + } + ] + }) + ); + expect(documentNode._set.calls.all()[1]).toEqual( + jasmine.objectContaining({ + object: documentNode, + args: [ + 'b', + { + global: 'rob', + subscripts: ['address', 'bar', 1] + } + ] + }) + ); }); it('should process array with offset', function () { @@ -127,14 +143,30 @@ describe(' - unit/proto/setDocument:', function () { documentNode.setDocument(obj, offset); expect(documentNode._set).toHaveBeenCalledTimes(2); - expect(documentNode._set.calls.argsFor(0)).toEqual(['a', { - global: 'rob', - subscripts: ['address', 'bar', 2] - }]); - expect(documentNode._set.calls.argsFor(1)).toEqual(['b', { - global: 'rob', - subscripts: ['address', 'bar', 3] - }]); + expect(documentNode._set.calls.all()[0]).toEqual( + jasmine.objectContaining({ + object: documentNode, + args: [ + 'a', + { + global: 'rob', + subscripts: ['address', 'bar', 2] + } + ] + }) + ); + expect(documentNode._set.calls.all()[1]).toEqual( + jasmine.objectContaining({ + object: documentNode, + args: [ + 'b', + { + global: 'rob', + subscripts: ['address', 'bar', 3] + } + ] + }) + ); }); it('should process when array item is object', function () { @@ -148,7 +180,7 @@ describe(' - unit/proto/setDocument:', function () { documentNode.setDocument(obj); - expect(documentNode._set).toHaveBeenCalledWith('baz', { + expect(documentNode._set).toHaveBeenCalledWithContext(documentNode, 'baz', { global: 'rob', subscripts: ['address', 'bar', 0, 'foo'] }); @@ -163,7 +195,7 @@ describe(' - unit/proto/setDocument:', function () { documentNode.setDocument(obj); - expect(documentNode._set).toHaveBeenCalledWith('baz', { + expect(documentNode._set).toHaveBeenCalledWithContext(documentNode, 'baz', { global: 'rob', subscripts: ['address', 'bar', 'foo'] }); diff --git a/spec/unit/proto/unlock.spec.js b/spec/unit/proto/unlock.spec.js new file mode 100644 index 0000000..95557b5 --- /dev/null +++ b/spec/unit/proto/unlock.spec.js @@ -0,0 +1,48 @@ +'use strict'; + +var unlock = require('../../../lib/proto/unlock'); +var dbMock = require('../mocks/db'); + +describe('unit/proto/unlock:', function () { + var DocumentStore; + var documentStore; + var DocumentNode; + var documentNode; + var db; + + beforeAll(function () { + DocumentNode = function (documentStore) { + this.documentStore = documentStore; + + this.documentName = 'rob'; + this.path = ['foo']; + this._node = { + global: 'rob', + subscripts: ['foo'] + }; + + this.unlock = unlock; + }; + + DocumentStore = function (db) { + this.db = db; + this.emit = jasmine.createSpy(); + this.DocumentNode = DocumentNode.bind(undefined, this); + }; + }); + + beforeEach(function () { + db = dbMock.mock(); + documentStore = new DocumentStore(db); + documentNode = new documentStore.DocumentNode(); + }); + + it('should unlock node', function () { + documentNode.unlock(); + + expect(documentStore.db.unlock).toHaveBeenCalledWith({ + global: 'rob', + subscripts: ['foo'] + }); + }); +}); diff --git a/spec/unit/proto/value.spec.js b/spec/unit/proto/value.spec.js index 1822fe5..6ba7559 100644 --- a/spec/unit/proto/value.spec.js +++ b/spec/unit/proto/value.spec.js @@ -3,7 +3,7 @@ var value = require('../../../lib/proto/value'); var dbMock = require('../mocks/db'); -describe(' - unit/proto/value:', function () { +describe('unit/proto/value:', function () { var DocumentStore; var documentStore; var DocumentNode; @@ -55,6 +55,6 @@ describe(' - unit/proto/value:', function () { documentNode.value = 'bar'; - expect(documentNode._set).toHaveBeenCalledWith('bar'); + expect(documentNode._set).toHaveBeenCalledWithContext(documentNode, 'bar'); }); });