forked from public/fvtt-cthulhu-eternal
Initial import with skill sheet working
This commit is contained in:
143
node_modules/abstract-level/test/async-iterator-test.js
generated
vendored
Normal file
143
node_modules/abstract-level/test/async-iterator-test.js
generated
vendored
Normal file
@ -0,0 +1,143 @@
|
||||
'use strict'
|
||||
|
||||
const input = [{ key: '1', value: '1' }, { key: '2', value: '2' }]
|
||||
|
||||
let db
|
||||
|
||||
exports.setup = function (test, testCommon) {
|
||||
test('setup', function (t) {
|
||||
t.plan(2)
|
||||
|
||||
db = testCommon.factory()
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open() error')
|
||||
|
||||
db.batch(input.map(entry => ({ ...entry, type: 'put' })), function (err) {
|
||||
t.ifError(err, 'no batch() error')
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
exports.asyncIterator = function (test, testCommon) {
|
||||
for (const mode of ['iterator', 'keys', 'values']) {
|
||||
test(`for await...of ${mode}()`, async function (t) {
|
||||
t.plan(1)
|
||||
|
||||
const it = db[mode]({ keyEncoding: 'utf8', valueEncoding: 'utf8' })
|
||||
const output = []
|
||||
|
||||
for await (const item of it) {
|
||||
output.push(item)
|
||||
}
|
||||
|
||||
t.same(output, input.map(({ key, value }) => {
|
||||
return mode === 'iterator' ? [key, value] : mode === 'keys' ? key : value
|
||||
}))
|
||||
})
|
||||
|
||||
testCommon.supports.permanence && test(`for await...of ${mode}() (deferred)`, async function (t) {
|
||||
t.plan(1)
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.batch(input.map(entry => ({ ...entry, type: 'put' })))
|
||||
await db.close()
|
||||
|
||||
// Don't await
|
||||
db.open()
|
||||
|
||||
const it = db[mode]({ keyEncoding: 'utf8', valueEncoding: 'utf8' })
|
||||
const output = []
|
||||
|
||||
for await (const item of it) {
|
||||
output.push(item)
|
||||
}
|
||||
|
||||
t.same(output, input.map(({ key, value }) => {
|
||||
return mode === 'iterator' ? [key, value] : mode === 'keys' ? key : value
|
||||
}))
|
||||
|
||||
await db.close()
|
||||
})
|
||||
|
||||
testCommon.supports.snapshots && test(`for await...of ${mode}() (deferred, with snapshot)`, async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
const db = testCommon.factory()
|
||||
const it = db[mode]({ keyEncoding: 'utf8', valueEncoding: 'utf8' })
|
||||
const promise = db.batch(input.map(entry => ({ ...entry, type: 'put' })))
|
||||
const output = []
|
||||
|
||||
for await (const item of it) {
|
||||
output.push(item)
|
||||
}
|
||||
|
||||
t.same(output, [], 'used snapshot')
|
||||
|
||||
// Wait for data to be written
|
||||
await promise
|
||||
|
||||
for await (const item of db[mode]({ keyEncoding: 'utf8', valueEncoding: 'utf8' })) {
|
||||
output.push(item)
|
||||
}
|
||||
|
||||
t.same(output, input.map(({ key, value }) => {
|
||||
return mode === 'iterator' ? [key, value] : mode === 'keys' ? key : value
|
||||
}))
|
||||
|
||||
await db.close()
|
||||
})
|
||||
|
||||
for (const deferred of [false, true]) {
|
||||
test(`for await...of ${mode}() (empty, deferred: ${deferred})`, async function (t) {
|
||||
const db = testCommon.factory()
|
||||
const entries = []
|
||||
|
||||
if (!deferred) await db.open()
|
||||
|
||||
for await (const item of db[mode]({ keyEncoding: 'utf8', valueEncoding: 'utf8' })) {
|
||||
entries.push(item)
|
||||
}
|
||||
|
||||
t.same(entries, [])
|
||||
await db.close()
|
||||
})
|
||||
}
|
||||
|
||||
test(`for await...of ${mode}() does not permit reuse`, async function (t) {
|
||||
t.plan(3)
|
||||
|
||||
const it = db[mode]()
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
for await (const item of it) {
|
||||
t.pass('nexted')
|
||||
}
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
for await (const item of it) {
|
||||
t.fail('should not be called')
|
||||
}
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
exports.teardown = function (test, testCommon) {
|
||||
test('teardown', function (t) {
|
||||
t.plan(1)
|
||||
|
||||
db.close(function (err) {
|
||||
t.ifError(err, 'no close() error')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.setup(test, testCommon)
|
||||
exports.asyncIterator(test, testCommon)
|
||||
exports.teardown(test, testCommon)
|
||||
}
|
320
node_modules/abstract-level/test/batch-test.js
generated
vendored
Normal file
320
node_modules/abstract-level/test/batch-test.js
generated
vendored
Normal file
@ -0,0 +1,320 @@
|
||||
'use strict'
|
||||
|
||||
const { Buffer } = require('buffer')
|
||||
const { verifyNotFoundError, assertAsync } = require('./util')
|
||||
const { illegalKeys, illegalValues } = require('./util')
|
||||
|
||||
let db
|
||||
|
||||
exports.setUp = function (test, testCommon) {
|
||||
test('setUp db', function (t) {
|
||||
db = testCommon.factory()
|
||||
db.open(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.args = function (test, testCommon) {
|
||||
test('test batch() with missing `value`', assertAsync.ctx(function (t) {
|
||||
t.plan(3)
|
||||
|
||||
db.batch([{ type: 'put', key: 'foo1' }], assertAsync(function (err) {
|
||||
t.is(err && err.code, 'LEVEL_INVALID_VALUE', 'correct error code (callback)')
|
||||
}))
|
||||
|
||||
db.batch([{ type: 'put', key: 'foo1' }]).catch((err) => {
|
||||
t.is(err.code, 'LEVEL_INVALID_VALUE', 'correct error code (promise)')
|
||||
})
|
||||
}))
|
||||
|
||||
test('test batch() with illegal values', assertAsync.ctx(function (t) {
|
||||
t.plan(illegalValues.length * 6)
|
||||
|
||||
for (const { name, value } of illegalValues) {
|
||||
db.batch([{ type: 'put', key: 'foo1', value }], assertAsync(function (err) {
|
||||
t.ok(err, name + ' - has error (callback)')
|
||||
t.ok(err instanceof Error, name + ' - is Error (callback)')
|
||||
t.is(err && err.code, 'LEVEL_INVALID_VALUE', 'correct error code (callback)')
|
||||
}))
|
||||
|
||||
db.batch([{ type: 'put', key: 'foo1', value }]).catch(function (err) {
|
||||
t.ok(err instanceof Error, name + ' - is Error (promise)')
|
||||
t.is(err.code, 'LEVEL_INVALID_VALUE', name + ' - correct error code (promise)')
|
||||
})
|
||||
}
|
||||
}))
|
||||
|
||||
test('test batch() with missing `key`', assertAsync.ctx(function (t) {
|
||||
t.plan(3)
|
||||
|
||||
db.batch([{ type: 'put', value: 'foo1' }], assertAsync(function (err) {
|
||||
t.is(err && err.code, 'LEVEL_INVALID_KEY', 'correct error code (callback)')
|
||||
}))
|
||||
|
||||
db.batch([{ type: 'put', value: 'foo1' }]).catch(function (err) {
|
||||
t.is(err.code, 'LEVEL_INVALID_KEY', 'correct error code (promise)')
|
||||
})
|
||||
}))
|
||||
|
||||
test('test batch() with illegal keys', assertAsync.ctx(function (t) {
|
||||
t.plan(illegalKeys.length * 6)
|
||||
|
||||
for (const { name, key } of illegalKeys) {
|
||||
db.batch([{ type: 'put', key, value: 'foo1' }], assertAsync(function (err) {
|
||||
t.ok(err, name + ' - has error (callback)')
|
||||
t.ok(err instanceof Error, name + ' - is Error (callback)')
|
||||
t.is(err && err.code, 'LEVEL_INVALID_KEY', 'correct error code (callback)')
|
||||
}))
|
||||
|
||||
db.batch([{ type: 'put', key, value: 'foo1' }]).catch(function (err) {
|
||||
t.ok(err instanceof Error, name + ' - is Error (promise)')
|
||||
t.is(err.code, 'LEVEL_INVALID_KEY', name + ' - correct error code (promise)')
|
||||
})
|
||||
}
|
||||
}))
|
||||
|
||||
test('test batch() with missing or incorrect type', assertAsync.ctx(function (t) {
|
||||
t.plan(10)
|
||||
|
||||
db.batch([{ key: 'key', value: 'value' }], assertAsync(function (err) {
|
||||
t.is(err && err.name, 'TypeError')
|
||||
t.is(err && err.message, "A batch operation must have a type property that is 'put' or 'del'", 'correct error message (callback)')
|
||||
}))
|
||||
|
||||
db.batch([{ key: 'key', value: 'value', type: 'foo' }], assertAsync(function (err) {
|
||||
t.is(err && err.name, 'TypeError')
|
||||
t.is(err && err.message, "A batch operation must have a type property that is 'put' or 'del'", 'correct error message (callback)')
|
||||
}))
|
||||
|
||||
db.batch([{ key: 'key', value: 'value' }]).catch(function (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err.message, "A batch operation must have a type property that is 'put' or 'del'", 'correct error message (promise)')
|
||||
})
|
||||
|
||||
db.batch([{ key: 'key', value: 'value', type: 'foo' }]).catch(function (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err.message, "A batch operation must have a type property that is 'put' or 'del'", 'correct error message (promise)')
|
||||
})
|
||||
}))
|
||||
|
||||
test('test batch() with missing or nullish operations', assertAsync.ctx(function (t) {
|
||||
t.plan(13)
|
||||
|
||||
db.batch(assertAsync(function (err) {
|
||||
t.is(err && err.name, 'TypeError')
|
||||
t.is(err && err.message, "The first argument 'operations' must be an array", 'correct error message (callback)')
|
||||
}))
|
||||
|
||||
for (const array of [null, undefined]) {
|
||||
db.batch(array, assertAsync(function (err) {
|
||||
t.is(err && err.name, 'TypeError')
|
||||
t.is(err && err.message, "The first argument 'operations' must be an array", 'correct error message (callback)')
|
||||
}))
|
||||
|
||||
db.batch(array).catch(function (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err.message, "The first argument 'operations' must be an array", 'correct error message (promise)')
|
||||
})
|
||||
}
|
||||
}))
|
||||
|
||||
test('test batch() with null options', function (t) {
|
||||
t.plan(2)
|
||||
|
||||
db.batch([], null, function (err) {
|
||||
t.error(err)
|
||||
})
|
||||
|
||||
db.batch([], null).then(function () {
|
||||
t.pass('resolved')
|
||||
}).catch(t.fail.bind(t))
|
||||
})
|
||||
|
||||
;[null, undefined, 1, true].forEach(function (operation) {
|
||||
const type = operation === null ? 'null' : typeof operation
|
||||
|
||||
test('test batch() with ' + type + ' operation', assertAsync.ctx(function (t) {
|
||||
t.plan(5)
|
||||
|
||||
db.batch([operation], assertAsync(function (err) {
|
||||
t.is(err && err.name, 'TypeError')
|
||||
t.is(err && err.message, 'A batch operation must be an object', 'correct error message (callback)')
|
||||
}))
|
||||
|
||||
db.batch([operation]).catch(function (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err.message, 'A batch operation must be an object', 'correct error message (promise)')
|
||||
})
|
||||
}))
|
||||
})
|
||||
|
||||
test('test batch() with empty array', assertAsync.ctx(function (t) {
|
||||
t.plan(3)
|
||||
|
||||
db.batch([], assertAsync(function (err) {
|
||||
t.error(err, 'no error from batch()')
|
||||
}))
|
||||
|
||||
db.batch([]).then(function () {
|
||||
t.pass('resolved')
|
||||
}).catch(t.fail.bind(t))
|
||||
}))
|
||||
}
|
||||
|
||||
exports.batch = function (test, testCommon) {
|
||||
test('test simple batch()', function (t) {
|
||||
db.batch([{ type: 'put', key: 'foo', value: 'bar' }], function (err) {
|
||||
t.error(err)
|
||||
|
||||
db.get('foo', function (err, value) {
|
||||
t.error(err)
|
||||
t.is(value, 'bar')
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('test simple batch() with promise', async function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
await db.open()
|
||||
await db.batch([{ type: 'put', key: 'foo', value: 'bar' }])
|
||||
|
||||
t.is(await db.get('foo', { valueEncoding: 'utf8' }), 'bar')
|
||||
return db.close()
|
||||
})
|
||||
|
||||
test('test multiple batch()', function (t) {
|
||||
db.batch([
|
||||
{ type: 'put', key: 'foobatch1', value: 'bar1' },
|
||||
{ type: 'put', key: 'foobatch2', value: 'bar2' },
|
||||
{ type: 'put', key: 'foobatch3', value: 'bar3' },
|
||||
{ type: 'del', key: 'foobatch2' }
|
||||
], function (err) {
|
||||
t.error(err)
|
||||
|
||||
let r = 0
|
||||
const done = function () {
|
||||
if (++r === 3) { t.end() }
|
||||
}
|
||||
|
||||
db.get('foobatch1', function (err, value) {
|
||||
t.error(err)
|
||||
t.is(value, 'bar1')
|
||||
done()
|
||||
})
|
||||
|
||||
db.get('foobatch2', function (err, value) {
|
||||
t.ok(err, 'entry not found')
|
||||
t.ok(typeof value === 'undefined', 'value is undefined')
|
||||
t.ok(verifyNotFoundError(err), 'NotFound error')
|
||||
done()
|
||||
})
|
||||
|
||||
db.get('foobatch3', function (err, value) {
|
||||
t.error(err)
|
||||
t.is(value, 'bar3')
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
for (const encoding of ['utf8', 'buffer', 'view']) {
|
||||
if (!testCommon.supports.encodings[encoding]) continue
|
||||
|
||||
// NOTE: adapted from memdown
|
||||
test(`empty values in batch with ${encoding} valueEncoding`, async function (t) {
|
||||
const db = testCommon.factory({ valueEncoding: encoding })
|
||||
const values = ['', Uint8Array.from([]), Buffer.alloc(0)]
|
||||
const expected = encoding === 'utf8' ? values[0] : encoding === 'view' ? values[1] : values[2]
|
||||
|
||||
await db.open()
|
||||
await db.batch(values.map((value, i) => ({ type: 'put', key: String(i), value })))
|
||||
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
const value = await db.get(String(i))
|
||||
|
||||
// Buffer is a Uint8Array, so this is allowed
|
||||
if (encoding === 'view' && Buffer.isBuffer(value)) {
|
||||
t.same(value, values[2])
|
||||
} else {
|
||||
t.same(value, expected)
|
||||
}
|
||||
}
|
||||
|
||||
return db.close()
|
||||
})
|
||||
|
||||
test(`empty keys in batch with ${encoding} keyEncoding`, async function (t) {
|
||||
const db = testCommon.factory({ keyEncoding: encoding })
|
||||
const keys = ['', Uint8Array.from([]), Buffer.alloc(0)]
|
||||
|
||||
await db.open()
|
||||
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
await db.batch([{ type: 'put', key: keys[i], value: String(i) }])
|
||||
t.same(await db.get(keys[i]), String(i), `got value ${i}`)
|
||||
}
|
||||
|
||||
return db.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
exports.atomic = function (test, testCommon) {
|
||||
test('test batch() is atomic', function (t) {
|
||||
t.plan(4)
|
||||
|
||||
let async = false
|
||||
|
||||
db.batch([
|
||||
{ type: 'put', key: 'foobah1', value: 'bar1' },
|
||||
{ type: 'put', value: 'bar2' },
|
||||
{ type: 'put', key: 'foobah3', value: 'bar3' }
|
||||
], function (err) {
|
||||
t.ok(err, 'should error')
|
||||
t.ok(async, 'callback is asynchronous')
|
||||
|
||||
db.get('foobah1', function (err) {
|
||||
t.ok(err, 'should not be found')
|
||||
})
|
||||
db.get('foobah3', function (err) {
|
||||
t.ok(err, 'should not be found')
|
||||
})
|
||||
})
|
||||
|
||||
async = true
|
||||
})
|
||||
}
|
||||
|
||||
exports.events = function (test, testCommon) {
|
||||
test('test batch([]) (array-form) emits batch event', async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
|
||||
t.ok(db.supports.events.batch)
|
||||
|
||||
db.on('batch', function (ops) {
|
||||
t.same(ops, [{ type: 'put', key: 456, value: 99, custom: 123 }])
|
||||
})
|
||||
|
||||
await db.batch([{ type: 'put', key: 456, value: 99, custom: 123 }])
|
||||
await db.close()
|
||||
})
|
||||
}
|
||||
|
||||
exports.tearDown = function (test, testCommon) {
|
||||
test('tearDown', function (t) {
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.setUp(test, testCommon)
|
||||
exports.args(test, testCommon)
|
||||
exports.batch(test, testCommon)
|
||||
exports.atomic(test, testCommon)
|
||||
exports.events(test, testCommon)
|
||||
exports.tearDown(test, testCommon)
|
||||
}
|
295
node_modules/abstract-level/test/chained-batch-test.js
generated
vendored
Normal file
295
node_modules/abstract-level/test/chained-batch-test.js
generated
vendored
Normal file
@ -0,0 +1,295 @@
|
||||
'use strict'
|
||||
|
||||
let db
|
||||
|
||||
exports.setUp = function (test, testCommon) {
|
||||
test('setUp db', function (t) {
|
||||
db = testCommon.factory()
|
||||
db.open(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.args = function (test, testCommon) {
|
||||
test('test batch has db reference', function (t) {
|
||||
t.ok(db.batch().db === db)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('test batch#put() with missing, null or undefined `value`', function (t) {
|
||||
t.plan(3 * 2)
|
||||
|
||||
for (const args of [[null], [undefined], []]) {
|
||||
const batch = db.batch()
|
||||
|
||||
try {
|
||||
batch.put('key', ...args)
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_INVALID_VALUE', 'correct error code')
|
||||
t.is(batch.length, 0, 'length is not incremented on error')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('test batch#put() with missing, null or undefined `key`', function (t) {
|
||||
t.plan(3 * 2)
|
||||
|
||||
for (const args of [[], [null, 'foo'], [undefined, 'foo']]) {
|
||||
const batch = db.batch()
|
||||
|
||||
try {
|
||||
batch.put(...args)
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_INVALID_KEY', 'correct error code')
|
||||
t.is(batch.length, 0, 'length is not incremented on error')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('test batch#del() with missing, null or undefined `key`', function (t) {
|
||||
t.plan(3 * 2)
|
||||
|
||||
for (const args of [[null], [undefined], []]) {
|
||||
const batch = db.batch()
|
||||
|
||||
try {
|
||||
batch.del(...args)
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_INVALID_KEY', 'correct error code')
|
||||
t.is(batch.length, 0, 'length is not incremented on error')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('test batch#clear() doesn\'t throw', function (t) {
|
||||
db.batch().clear()
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('test batch#put() after write()', function (t) {
|
||||
const batch = db.batch().put('foo', 'bar')
|
||||
batch.write(function () {})
|
||||
try {
|
||||
batch.put('boom', 'bang')
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_BATCH_NOT_OPEN', 'correct error code')
|
||||
return t.end()
|
||||
}
|
||||
t.fail('should have thrown')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('test batch#del() after write()', function (t) {
|
||||
const batch = db.batch().put('foo', 'bar')
|
||||
batch.write(function () {})
|
||||
try {
|
||||
batch.del('foo')
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_BATCH_NOT_OPEN', 'correct error code')
|
||||
return t.end()
|
||||
}
|
||||
t.fail('should have thrown')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('test batch#clear() after write()', function (t) {
|
||||
const batch = db.batch().put('foo', 'bar')
|
||||
batch.write(function () {})
|
||||
try {
|
||||
batch.clear()
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_BATCH_NOT_OPEN', 'correct error code')
|
||||
return t.end()
|
||||
}
|
||||
t.fail('should have thrown')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('test batch#write() after write()', function (t) {
|
||||
t.plan(1)
|
||||
const batch = db.batch().put('foo', 'bar')
|
||||
batch.write(function () {})
|
||||
batch.write(function (err) {
|
||||
t.is(err && err.code, 'LEVEL_BATCH_NOT_OPEN', 'correct error code')
|
||||
})
|
||||
})
|
||||
|
||||
test('test batch#write() with no operations', function (t) {
|
||||
let async = false
|
||||
|
||||
db.batch().write(function (err) {
|
||||
t.ifError(err, 'no error from write()')
|
||||
t.ok(async, 'callback is asynchronous')
|
||||
t.end()
|
||||
})
|
||||
|
||||
async = true
|
||||
})
|
||||
|
||||
test('test batch#write() with promise and no operations', function (t) {
|
||||
db.batch().write()
|
||||
.then(t.end.bind(t))
|
||||
.catch(t.end.bind(t))
|
||||
})
|
||||
|
||||
test('test twice batch#close() is idempotent', function (t) {
|
||||
const batch = db.batch()
|
||||
batch.close(function () {
|
||||
let async = false
|
||||
|
||||
batch.close(function () {
|
||||
t.ok(async, 'callback is asynchronous')
|
||||
t.end()
|
||||
})
|
||||
|
||||
async = true
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
exports.batch = function (test, testCommon) {
|
||||
test('test basic batch', function (t) {
|
||||
db.batch([
|
||||
{ type: 'put', key: 'one', value: '1' },
|
||||
{ type: 'put', key: 'two', value: '2' },
|
||||
{ type: 'put', key: 'three', value: '3' }
|
||||
], function (err) {
|
||||
t.error(err)
|
||||
|
||||
const batch = db.batch()
|
||||
.put('1', 'one')
|
||||
.del('2', 'two')
|
||||
.put('3', 'three')
|
||||
|
||||
t.is(batch.length, 3, 'length was incremented')
|
||||
|
||||
batch.clear()
|
||||
t.is(batch.length, 0, 'length is reset')
|
||||
|
||||
batch.put('one', 'I')
|
||||
.put('two', 'II')
|
||||
.del('three')
|
||||
.put('foo', 'bar')
|
||||
|
||||
t.is(batch.length, 4, 'length was incremented')
|
||||
|
||||
batch.write(function (err) {
|
||||
t.error(err, 'no write() error')
|
||||
|
||||
db.iterator({ keyEncoding: 'utf8', valueEncoding: 'utf8' }).all(function (err, entries) {
|
||||
t.error(err)
|
||||
t.same(entries, [
|
||||
['foo', 'bar'],
|
||||
['one', 'I'],
|
||||
['two', 'II']
|
||||
])
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('test basic batch with promise', function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.error(err)
|
||||
|
||||
db.batch()
|
||||
.put('1', 'one')
|
||||
.put('2', 'two')
|
||||
.put('3', 'three')
|
||||
.write().then(function () {
|
||||
db.iterator({ keyEncoding: 'utf8', valueEncoding: 'utf8' }).all(function (err, entries) {
|
||||
t.error(err)
|
||||
t.same(entries, [
|
||||
['1', 'one'],
|
||||
['2', 'two'],
|
||||
['3', 'three']
|
||||
])
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
}).catch(t.fail.bind(t))
|
||||
})
|
||||
})
|
||||
|
||||
// NOTE: adapted from levelup
|
||||
test('chained batch with per-operation encoding options', async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
|
||||
db.once('batch', function (operations) {
|
||||
t.same(operations, [
|
||||
{ type: 'put', key: 'a', value: 'a', valueEncoding: 'json' },
|
||||
{ type: 'put', key: 'b', value: 'b' },
|
||||
{ type: 'put', key: '"c"', value: 'c' },
|
||||
{ type: 'del', key: 'c', keyEncoding: 'json', arbitraryOption: true }
|
||||
])
|
||||
})
|
||||
|
||||
await db.batch()
|
||||
.put('a', 'a', { valueEncoding: 'json' })
|
||||
.put('b', 'b')
|
||||
.put('"c"', 'c')
|
||||
.del('c', { keyEncoding: 'json', arbitraryOption: true })
|
||||
.write()
|
||||
|
||||
t.same(await db.iterator().all(), [
|
||||
['a', '"a"'],
|
||||
['b', 'b']
|
||||
])
|
||||
|
||||
return db.close()
|
||||
})
|
||||
}
|
||||
|
||||
exports.events = function (test, testCommon) {
|
||||
test('test chained batch() emits batch event', async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
|
||||
t.ok(db.supports.events.batch)
|
||||
|
||||
db.on('batch', function (ops) {
|
||||
t.same(ops, [
|
||||
{ type: 'put', key: 987, value: 'b', custom: 123 },
|
||||
{ type: 'del', key: 216, custom: 999 }
|
||||
])
|
||||
})
|
||||
|
||||
await db.batch().put(987, 'b', { custom: 123 }).del(216, { custom: 999 }).write()
|
||||
await db.close()
|
||||
})
|
||||
|
||||
test('test close() on chained batch event', async function () {
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
|
||||
let promise
|
||||
|
||||
db.on('batch', function () {
|
||||
// Should not interfere with the current write() operation
|
||||
promise = db.close()
|
||||
})
|
||||
|
||||
await db.batch().put('a', 'b').write()
|
||||
await promise
|
||||
})
|
||||
}
|
||||
|
||||
exports.tearDown = function (test, testCommon) {
|
||||
test('tearDown', function (t) {
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.setUp(test, testCommon)
|
||||
exports.args(test, testCommon)
|
||||
exports.batch(test, testCommon)
|
||||
exports.events(test, testCommon)
|
||||
exports.tearDown(test, testCommon)
|
||||
}
|
274
node_modules/abstract-level/test/clear-range-test.js
generated
vendored
Normal file
274
node_modules/abstract-level/test/clear-range-test.js
generated
vendored
Normal file
@ -0,0 +1,274 @@
|
||||
'use strict'
|
||||
|
||||
const data = (function () {
|
||||
const d = []
|
||||
let i = 0
|
||||
let k
|
||||
for (; i < 100; i++) {
|
||||
k = (i < 10 ? '0' : '') + i
|
||||
d.push({
|
||||
key: k,
|
||||
value: String(Math.random())
|
||||
})
|
||||
}
|
||||
return d
|
||||
}())
|
||||
|
||||
exports.range = function (test, testCommon) {
|
||||
function rangeTest (name, opts, expected) {
|
||||
test('db#clear() with ' + name, function (t) {
|
||||
prepare(t, function (db) {
|
||||
db.clear(opts, function (err) {
|
||||
t.ifError(err, 'no clear error')
|
||||
verify(t, db, expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function prepare (t, callback) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open error')
|
||||
|
||||
db.batch(data.map(function (d) {
|
||||
return {
|
||||
type: 'put',
|
||||
key: d.key,
|
||||
value: d.value
|
||||
}
|
||||
}), function (err) {
|
||||
t.ifError(err, 'no batch error')
|
||||
callback(db)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function verify (t, db, expected) {
|
||||
const it = db.iterator({ keyEncoding: 'utf8', valueEncoding: 'utf8' })
|
||||
|
||||
it.all(function (err, entries) {
|
||||
t.ifError(err, 'no all() error')
|
||||
t.is(entries.length, expected.length, 'correct number of entries')
|
||||
t.same(entries, expected.map(kv => [kv.key, kv.value]))
|
||||
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
function exclude (data, start, end, expectedLength) {
|
||||
data = data.slice()
|
||||
const removed = data.splice(start, end - start + 1) // Inclusive
|
||||
if (expectedLength != null) checkLength(removed, expectedLength)
|
||||
return data
|
||||
}
|
||||
|
||||
// For sanity checks on test arguments
|
||||
function checkLength (arr, length) {
|
||||
if (arr.length !== length) {
|
||||
throw new RangeError('Expected ' + length + ' elements, got ' + arr.length)
|
||||
}
|
||||
|
||||
return arr
|
||||
}
|
||||
|
||||
rangeTest('full range', {}, [])
|
||||
|
||||
// Reversing has no effect without limit
|
||||
rangeTest('reverse=true', {
|
||||
reverse: true
|
||||
}, [])
|
||||
|
||||
rangeTest('gte=00', {
|
||||
gte: '00'
|
||||
}, [])
|
||||
|
||||
rangeTest('gte=50', {
|
||||
gte: '50'
|
||||
}, data.slice(0, 50))
|
||||
|
||||
rangeTest('lte=50 and reverse=true', {
|
||||
lte: '50',
|
||||
reverse: true
|
||||
}, data.slice(51))
|
||||
|
||||
rangeTest('gte=49.5 (midway)', {
|
||||
gte: '49.5'
|
||||
}, data.slice(0, 50))
|
||||
|
||||
rangeTest('gte=49999 (midway)', {
|
||||
gte: '49999'
|
||||
}, data.slice(0, 50))
|
||||
|
||||
rangeTest('lte=49.5 (midway) and reverse=true', {
|
||||
lte: '49.5',
|
||||
reverse: true
|
||||
}, data.slice(50))
|
||||
|
||||
rangeTest('lt=49.5 (midway) and reverse=true', {
|
||||
lt: '49.5',
|
||||
reverse: true
|
||||
}, data.slice(50))
|
||||
|
||||
rangeTest('lt=50 and reverse=true', {
|
||||
lt: '50',
|
||||
reverse: true
|
||||
}, data.slice(50))
|
||||
|
||||
rangeTest('lte=50', {
|
||||
lte: '50'
|
||||
}, data.slice(51))
|
||||
|
||||
rangeTest('lte=50.5 (midway)', {
|
||||
lte: '50.5'
|
||||
}, data.slice(51))
|
||||
|
||||
rangeTest('lte=50555 (midway)', {
|
||||
lte: '50555'
|
||||
}, data.slice(51))
|
||||
|
||||
rangeTest('lt=50555 (midway)', {
|
||||
lt: '50555'
|
||||
}, data.slice(51))
|
||||
|
||||
rangeTest('gte=50.5 (midway) and reverse=true', {
|
||||
gte: '50.5',
|
||||
reverse: true
|
||||
}, data.slice(0, 51))
|
||||
|
||||
rangeTest('gt=50.5 (midway) and reverse=true', {
|
||||
gt: '50.5',
|
||||
reverse: true
|
||||
}, data.slice(0, 51))
|
||||
|
||||
rangeTest('gt=50 and reverse=true', {
|
||||
gt: '50',
|
||||
reverse: true
|
||||
}, data.slice(0, 51))
|
||||
|
||||
// First key is actually '00' so it should avoid it
|
||||
rangeTest('lte=0', {
|
||||
lte: '0'
|
||||
}, data)
|
||||
|
||||
// First key is actually '00' so it should avoid it
|
||||
rangeTest('lt=0', {
|
||||
lt: '0'
|
||||
}, data)
|
||||
|
||||
rangeTest('gte=30 and lte=70', {
|
||||
gte: '30',
|
||||
lte: '70'
|
||||
}, exclude(data, 30, 70))
|
||||
|
||||
// The gte and lte options should take precedence over gt and lt respectively.
|
||||
rangeTest('test iterator with gte=30 and lte=70 and gt=40 and lt=60', {
|
||||
gte: '30',
|
||||
lte: '70',
|
||||
gt: '40',
|
||||
lt: '60'
|
||||
}, exclude(data, 30, 70))
|
||||
|
||||
// Also test the other way around: if gt and lt were to select a bigger range.
|
||||
rangeTest('test iterator with gte=30 and lte=70 and gt=20 and lt=80', {
|
||||
gte: '30',
|
||||
lte: '70',
|
||||
gt: '20',
|
||||
lt: '80'
|
||||
}, exclude(data, 30, 70))
|
||||
|
||||
rangeTest('gt=29 and lt=71', {
|
||||
gt: '29',
|
||||
lt: '71'
|
||||
}, exclude(data, 30, 70))
|
||||
|
||||
rangeTest('gte=30 and lte=70 and reverse=true', {
|
||||
lte: '70',
|
||||
gte: '30',
|
||||
reverse: true
|
||||
}, exclude(data, 30, 70))
|
||||
|
||||
rangeTest('gt=29 and lt=71 and reverse=true', {
|
||||
lt: '71',
|
||||
gt: '29',
|
||||
reverse: true
|
||||
}, exclude(data, 30, 70))
|
||||
|
||||
rangeTest('limit=20', {
|
||||
limit: 20
|
||||
}, data.slice(20))
|
||||
|
||||
rangeTest('limit=20 and gte=20', {
|
||||
limit: 20,
|
||||
gte: '20'
|
||||
}, exclude(data, 20, 39, 20))
|
||||
|
||||
rangeTest('limit=20 and reverse=true', {
|
||||
limit: 20,
|
||||
reverse: true
|
||||
}, data.slice(0, -20))
|
||||
|
||||
rangeTest('limit=20 and lte=79 and reverse=true', {
|
||||
limit: 20,
|
||||
lte: '79',
|
||||
reverse: true
|
||||
}, exclude(data, 60, 79, 20))
|
||||
|
||||
rangeTest('limit=-1 should clear whole database', {
|
||||
limit: -1
|
||||
}, [])
|
||||
|
||||
rangeTest('limit=0 should not clear anything', {
|
||||
limit: 0
|
||||
}, data)
|
||||
|
||||
rangeTest('lte after limit', {
|
||||
limit: 20,
|
||||
lte: '50'
|
||||
}, data.slice(20))
|
||||
|
||||
rangeTest('lte before limit', {
|
||||
limit: 50,
|
||||
lte: '19'
|
||||
}, data.slice(20))
|
||||
|
||||
rangeTest('gte after database end', {
|
||||
gte: '9a'
|
||||
}, data)
|
||||
|
||||
rangeTest('gt after database end', {
|
||||
gt: '9a'
|
||||
}, data)
|
||||
|
||||
rangeTest('lte after database end and reverse=true', {
|
||||
lte: '9a',
|
||||
reverse: true
|
||||
}, [])
|
||||
|
||||
rangeTest('lte and gte after database and reverse=true', {
|
||||
lte: '9b',
|
||||
gte: '9a',
|
||||
reverse: true
|
||||
}, data)
|
||||
|
||||
rangeTest('lt and gt after database and reverse=true', {
|
||||
lt: '9b',
|
||||
gt: '9a',
|
||||
reverse: true
|
||||
}, data)
|
||||
|
||||
rangeTest('gt greater than lt', {
|
||||
gt: '20',
|
||||
lt: '10'
|
||||
}, data)
|
||||
|
||||
rangeTest('gte greater than lte', {
|
||||
gte: '20',
|
||||
lte: '10'
|
||||
}, data)
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.range(test, testCommon)
|
||||
}
|
183
node_modules/abstract-level/test/clear-test.js
generated
vendored
Normal file
183
node_modules/abstract-level/test/clear-test.js
generated
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
'use strict'
|
||||
|
||||
const isBuffer = require('is-buffer')
|
||||
const { Buffer } = require('buffer')
|
||||
|
||||
exports.args = function (test, testCommon) {
|
||||
test('test clear() with legacy range options', function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err)
|
||||
|
||||
try {
|
||||
db.clear({ start: 'foo' }, t.fail.bind(t))
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_LEGACY')
|
||||
}
|
||||
|
||||
try {
|
||||
db.clear({ end: 'foo' }).catch(t.fail.bind(t))
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_LEGACY')
|
||||
}
|
||||
|
||||
db.close(t.ifError.bind(t))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
exports.clear = function (test, testCommon) {
|
||||
makeTest('string', ['a', 'b'])
|
||||
|
||||
if (testCommon.supports.encodings.buffer) {
|
||||
makeTest('buffer', [Buffer.from('a'), Buffer.from('b')])
|
||||
makeTest('mixed', [Buffer.from('a'), 'b'])
|
||||
|
||||
// These keys would be equal when compared as utf8 strings
|
||||
makeTest('non-utf8 buffer', [Buffer.from('80', 'hex'), Buffer.from('c0', 'hex')])
|
||||
}
|
||||
|
||||
function makeTest (type, keys) {
|
||||
test('test simple clear() on ' + type + ' keys', function (t) {
|
||||
t.plan(8)
|
||||
|
||||
const db = testCommon.factory()
|
||||
const ops = keys.map(function (key) {
|
||||
return { type: 'put', key: key, value: 'foo', keyEncoding: isBuffer(key) ? 'buffer' : 'utf8' }
|
||||
})
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open error')
|
||||
|
||||
db.batch(ops, function (err) {
|
||||
t.ifError(err, 'no batch error')
|
||||
|
||||
db.iterator().all(function (err, entries) {
|
||||
t.ifError(err, 'no all() error')
|
||||
t.is(entries.length, keys.length, 'has entries')
|
||||
|
||||
db.clear(function (err) {
|
||||
t.ifError(err, 'no clear error')
|
||||
|
||||
db.iterator().all(function (err, entries) {
|
||||
t.ifError(err, 'no all() error')
|
||||
t.is(entries.length, 0, 'has no entries')
|
||||
|
||||
db.close(function (err) {
|
||||
t.ifError(err, 'no close error')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('test simple clear() on ' + type + ' keys, with promise', function (t) {
|
||||
t.plan(8)
|
||||
|
||||
const db = testCommon.factory()
|
||||
const ops = keys.map(function (key) {
|
||||
return { type: 'put', key: key, value: 'foo', keyEncoding: isBuffer(key) ? 'buffer' : 'utf8' }
|
||||
})
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open error')
|
||||
|
||||
db.batch(ops, function (err) {
|
||||
t.ifError(err, 'no batch error')
|
||||
|
||||
db.iterator().all(function (err, entries) {
|
||||
t.ifError(err, 'no all() error')
|
||||
t.is(entries.length, keys.length, 'has entries')
|
||||
|
||||
db.clear().then(function () {
|
||||
t.ifError(err, 'no clear error')
|
||||
|
||||
db.iterator().all(function (err, entries) {
|
||||
t.ifError(err, 'no all() error')
|
||||
t.is(entries.length, 0, 'has no entries')
|
||||
|
||||
db.close(function (err) {
|
||||
t.ifError(err, 'no close error')
|
||||
})
|
||||
})
|
||||
}).catch(t.fail.bind(t))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// NOTE: adapted from levelup
|
||||
for (const deferred of [false, true]) {
|
||||
for (const [gte, keyEncoding] of [['"b"', 'utf8'], ['b', 'json']]) {
|
||||
test(`clear() with ${keyEncoding} encoding (deferred: ${deferred})`, async function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
await db.open()
|
||||
await db.batch([
|
||||
{ type: 'put', key: '"a"', value: 'a' },
|
||||
{ type: 'put', key: '"b"', value: 'b' }
|
||||
])
|
||||
|
||||
if (deferred) {
|
||||
await db.close()
|
||||
t.is(db.status, 'closed')
|
||||
db.open(t.ifError.bind(t))
|
||||
t.is(db.status, 'opening')
|
||||
}
|
||||
|
||||
await db.clear({ gte, keyEncoding })
|
||||
|
||||
const keys = await db.keys().all()
|
||||
t.same(keys, ['"a"'], 'got expected keys')
|
||||
|
||||
return db.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.events = function (test, testCommon) {
|
||||
test('test clear() with options emits clear event', async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
|
||||
t.ok(db.supports.events.clear)
|
||||
|
||||
db.on('clear', function (options) {
|
||||
t.same(options, { gt: 567, custom: 123 })
|
||||
})
|
||||
|
||||
await db.clear({ gt: 567, custom: 123 })
|
||||
await db.close()
|
||||
})
|
||||
|
||||
test('test clear() without options emits clear event', async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
|
||||
t.ok(db.supports.events.clear)
|
||||
|
||||
db.on('clear', function (options) {
|
||||
t.same(options, {})
|
||||
})
|
||||
|
||||
await db.clear()
|
||||
await db.close()
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.args(test, testCommon)
|
||||
exports.events(test, testCommon)
|
||||
exports.clear(test, testCommon)
|
||||
}
|
32
node_modules/abstract-level/test/close-test.js
generated
vendored
Normal file
32
node_modules/abstract-level/test/close-test.js
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
'use strict'
|
||||
|
||||
exports.close = function (test, testCommon) {
|
||||
test('test close()', function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open() error')
|
||||
|
||||
db.close(function (err) {
|
||||
t.error(err)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('test close() with promise', function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open() error')
|
||||
|
||||
db.close()
|
||||
.then(t.end.bind(t))
|
||||
.catch(t.end.bind(t))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.close(test, testCommon)
|
||||
}
|
90
node_modules/abstract-level/test/common.js
generated
vendored
Normal file
90
node_modules/abstract-level/test/common.js
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
'use strict'
|
||||
|
||||
const kNone = Symbol('none')
|
||||
const kProtected = Symbol('protected')
|
||||
|
||||
function testCommon (options) {
|
||||
const factory = options.factory
|
||||
const test = options.test
|
||||
|
||||
if (typeof factory !== 'function') {
|
||||
throw new TypeError('factory must be a function')
|
||||
}
|
||||
|
||||
if (typeof test !== 'function') {
|
||||
throw new TypeError('test must be a function')
|
||||
}
|
||||
|
||||
if (options.legacyRange != null) {
|
||||
throw new Error('The legacyRange option has been removed')
|
||||
}
|
||||
|
||||
let supports = kNone
|
||||
|
||||
return protect(options, {
|
||||
test: test,
|
||||
factory: factory,
|
||||
internals: options.internals || {},
|
||||
|
||||
// Expose manifest through testCommon to more easily skip tests based on
|
||||
// supported features. Use a getter to only create a db once. Implicitly
|
||||
// we also test that the manifest doesn't change after the db constructor.
|
||||
get supports () {
|
||||
if (supports === kNone) this.supports = this.factory().supports
|
||||
return supports
|
||||
},
|
||||
|
||||
// Prefer assigning early via manifest-test unless test.only() is used
|
||||
// in which case we create the manifest on-demand. Copy it to be safe.
|
||||
set supports (value) {
|
||||
if (supports === kNone) supports = JSON.parse(JSON.stringify(value))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = testCommon
|
||||
|
||||
// To help migrating from abstract-leveldown.
|
||||
// Throw if test suite options are used instead of db.supports
|
||||
function protect (options, testCommon) {
|
||||
const legacyOptions = [
|
||||
['createIfMissing', true],
|
||||
['errorIfExists', true],
|
||||
['snapshots', true],
|
||||
['seek', true],
|
||||
['encodings', true],
|
||||
['deferredOpen', true],
|
||||
['streams', true],
|
||||
['clear', true],
|
||||
['getMany', true],
|
||||
['bufferKeys', false],
|
||||
['serialize', false],
|
||||
['idempotentOpen', false],
|
||||
['passiveOpen', false],
|
||||
['openCallback', false]
|
||||
]
|
||||
|
||||
Object.defineProperty(testCommon, kProtected, {
|
||||
value: true
|
||||
})
|
||||
|
||||
for (const [k, exists] of legacyOptions) {
|
||||
const msg = exists ? 'has moved to db.supports' : 'has been removed'
|
||||
|
||||
// Options may be a testCommon instance
|
||||
if (!options[kProtected] && k in options) {
|
||||
throw new Error(`The test suite option '${k}' ${msg}`)
|
||||
}
|
||||
|
||||
Object.defineProperty(testCommon, k, {
|
||||
get () {
|
||||
throw new Error(`The test suite option '${k}' ${msg}`)
|
||||
},
|
||||
set () {
|
||||
throw new Error(`The test suite option '${k}' ${msg}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return testCommon
|
||||
}
|
329
node_modules/abstract-level/test/deferred-open-test.js
generated
vendored
Normal file
329
node_modules/abstract-level/test/deferred-open-test.js
generated
vendored
Normal file
@ -0,0 +1,329 @@
|
||||
'use strict'
|
||||
|
||||
const { DeferredIterator } = require('../lib/deferred-iterator')
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
function verifyValues (t, db, entries) {
|
||||
let pendingGets = 3
|
||||
|
||||
for (let k = 1; k <= entries; k++) {
|
||||
db.get('k' + k, { valueEncoding: 'utf8' }, function (err, v) {
|
||||
t.ifError(err, 'no get() error')
|
||||
t.is(v, 'v' + k, 'value is ok')
|
||||
t.is(db.status, 'open', 'status is ok')
|
||||
|
||||
if (--pendingGets <= 0) {
|
||||
db.get('k4', { valueEncoding: 'utf8' }, function (err) {
|
||||
t.ok(err)
|
||||
db.close(t.ifError.bind(t))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: copied from levelup
|
||||
test('deferred open(): put() and get() on new database', function (t) {
|
||||
t.plan(15)
|
||||
|
||||
// Open database without callback, opens in next tick
|
||||
const db = testCommon.factory()
|
||||
|
||||
let pendingPuts = 3
|
||||
|
||||
// Insert 3 values with put(), these should be deferred until the database is actually open
|
||||
for (let k = 1; k <= 3; k++) {
|
||||
db.put('k' + k, 'v' + k, function (err) {
|
||||
t.ifError(err, 'no put() error')
|
||||
|
||||
if (--pendingPuts <= 0) {
|
||||
verifyValues(t, db, 3)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
t.is(db.status, 'opening')
|
||||
})
|
||||
|
||||
// NOTE: copied from levelup
|
||||
test('deferred open(): batch() on new database', function (t) {
|
||||
t.plan(13)
|
||||
|
||||
// Open database without callback, opens in next tick
|
||||
const db = testCommon.factory()
|
||||
|
||||
// Insert 3 values with batch(), these should be deferred until the database is actually open
|
||||
db.batch([
|
||||
{ type: 'put', key: 'k1', value: 'v1' },
|
||||
{ type: 'put', key: 'k2', value: 'v2' },
|
||||
{ type: 'put', key: 'k3', value: 'v3' }
|
||||
], function (err) {
|
||||
t.ifError(err, 'no batch() error')
|
||||
verifyValues(t, db, 3)
|
||||
})
|
||||
|
||||
t.is(db.status, 'opening')
|
||||
})
|
||||
|
||||
// NOTE: copied from levelup
|
||||
test('deferred open(): chained batch() on new database', function (t) {
|
||||
t.plan(13)
|
||||
|
||||
// Open database without callback, opens in next tick
|
||||
const db = testCommon.factory()
|
||||
|
||||
// Insert 3 values with batch(), these should be deferred until the database is actually open
|
||||
db.batch()
|
||||
.put('k1', 'v1')
|
||||
.put('k2', 'v2')
|
||||
.put('k3', 'v3')
|
||||
.write(function (err) {
|
||||
t.ifError(err, 'no write() error')
|
||||
verifyValues(t, db, 3)
|
||||
})
|
||||
|
||||
t.is(db.status, 'opening')
|
||||
})
|
||||
|
||||
// NOTE: copied from levelup
|
||||
test('deferred open(): put() and get() on reopened database', async function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
await db.close()
|
||||
t.is(db.status, 'closed')
|
||||
|
||||
db.open(() => {})
|
||||
t.is(db.status, 'opening')
|
||||
|
||||
await db.put('beep', 'boop')
|
||||
|
||||
t.is(db.status, 'open')
|
||||
t.is(await db.get('beep', { valueEncoding: 'utf8' }), 'boop')
|
||||
|
||||
await db.close()
|
||||
})
|
||||
|
||||
// NOTE: copied from levelup
|
||||
test('deferred open(): value of queued operation is not stringified', function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = testCommon.factory({ valueEncoding: 'json' })
|
||||
|
||||
db.put('key', { thing: 2 }, function (err) {
|
||||
t.ifError(err)
|
||||
|
||||
db.get('key', function (err, value) {
|
||||
t.ifError(err)
|
||||
t.same(value, { thing: 2 })
|
||||
db.close(t.ifError.bind(t))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// NOTE: copied from levelup
|
||||
test('deferred open(): key of queued operation is not stringified', function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = testCommon.factory({ keyEncoding: 'json' })
|
||||
|
||||
db.put({ thing: 2 }, 'value', function (err) {
|
||||
t.ifError(err)
|
||||
|
||||
db.iterator().next(function (err, key, value) {
|
||||
t.ifError(err, 'no next() error')
|
||||
t.same(key, { thing: 2 })
|
||||
db.close(t.ifError.bind(t))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// NOTE: copied from deferred-leveldown
|
||||
test('cannot operate on closed db', function (t) {
|
||||
t.plan(6)
|
||||
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err)
|
||||
|
||||
db.close(function (err) {
|
||||
t.ifError(err)
|
||||
|
||||
db.put('foo', 'bar', function (err) {
|
||||
t.is(err && err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
})
|
||||
|
||||
try {
|
||||
db.iterator()
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
}
|
||||
|
||||
try {
|
||||
db.keys()
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
}
|
||||
|
||||
try {
|
||||
db.values()
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// NOTE: copied from deferred-leveldown
|
||||
test('cannot operate on closing db', function (t) {
|
||||
t.plan(6)
|
||||
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err)
|
||||
|
||||
db.close(function (err) {
|
||||
t.ifError(err)
|
||||
})
|
||||
|
||||
db.put('foo', 'bar', function (err) {
|
||||
t.is(err && err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
})
|
||||
|
||||
try {
|
||||
db.iterator()
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
}
|
||||
|
||||
try {
|
||||
db.keys()
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
}
|
||||
|
||||
try {
|
||||
db.values()
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// NOTE: copied from deferred-leveldown
|
||||
test('deferred iterator - cannot operate on closed db', function (t) {
|
||||
t.plan(10)
|
||||
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.error(err, 'no error')
|
||||
|
||||
db.close(function (err) {
|
||||
t.ifError(err)
|
||||
|
||||
it.next(function (err, key, value) {
|
||||
t.is(err && err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
})
|
||||
|
||||
it.next().catch(function (err) {
|
||||
t.is(err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
})
|
||||
|
||||
it.nextv(10, function (err, items) {
|
||||
t.is(err && err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
})
|
||||
|
||||
it.nextv(10).catch(function (err) {
|
||||
t.is(err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
})
|
||||
|
||||
it.all(function (err, items) {
|
||||
t.is(err && err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
})
|
||||
|
||||
it.all().catch(function (err) {
|
||||
t.is(err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
})
|
||||
|
||||
// Was already closed
|
||||
it.close(function () {
|
||||
t.ifError(err, 'no close() error')
|
||||
})
|
||||
|
||||
it.close().catch(function () {
|
||||
t.fail('no close() error')
|
||||
})
|
||||
|
||||
try {
|
||||
it.seek('foo')
|
||||
} catch (err) {
|
||||
// Should *not* throw
|
||||
t.fail(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const it = db.iterator({ gt: 'foo' })
|
||||
t.ok(it instanceof DeferredIterator)
|
||||
})
|
||||
|
||||
// NOTE: copied from deferred-leveldown
|
||||
test('deferred iterator - cannot operate on closing db', function (t) {
|
||||
t.plan(10)
|
||||
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.error(err, 'no error')
|
||||
|
||||
db.close(function (err) {
|
||||
t.ifError(err)
|
||||
})
|
||||
|
||||
it.next(function (err, key, value) {
|
||||
t.is(err && err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
})
|
||||
|
||||
it.next().catch(function (err) {
|
||||
t.is(err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
})
|
||||
|
||||
it.nextv(10, function (err) {
|
||||
t.is(err && err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
})
|
||||
|
||||
it.nextv(10).catch(function (err) {
|
||||
t.is(err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
})
|
||||
|
||||
it.all(function (err) {
|
||||
t.is(err && err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
})
|
||||
|
||||
it.all().catch(function (err) {
|
||||
t.is(err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
})
|
||||
|
||||
// Is already closing
|
||||
it.close(function (err) {
|
||||
t.ifError(err, 'no close() error')
|
||||
})
|
||||
|
||||
it.close().catch(function () {
|
||||
t.fail('no close() error')
|
||||
})
|
||||
|
||||
try {
|
||||
it.seek('foo')
|
||||
} catch (err) {
|
||||
// Should *not* throw
|
||||
t.fail(err)
|
||||
}
|
||||
})
|
||||
|
||||
const it = db.iterator({ gt: 'foo' })
|
||||
t.ok(it instanceof DeferredIterator)
|
||||
})
|
||||
}
|
105
node_modules/abstract-level/test/del-test.js
generated
vendored
Normal file
105
node_modules/abstract-level/test/del-test.js
generated
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
'use strict'
|
||||
|
||||
const { verifyNotFoundError, illegalKeys, assertAsync } = require('./util')
|
||||
|
||||
let db
|
||||
|
||||
exports.setUp = function (test, testCommon) {
|
||||
test('setUp db', function (t) {
|
||||
db = testCommon.factory()
|
||||
db.open(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.args = function (test, testCommon) {
|
||||
test('test del() with illegal keys', assertAsync.ctx(function (t) {
|
||||
t.plan(illegalKeys.length * 5)
|
||||
|
||||
for (const { name, key } of illegalKeys) {
|
||||
db.del(key, assertAsync(function (err) {
|
||||
t.ok(err instanceof Error, name + ' - is Error (callback)')
|
||||
t.is(err && err.code, 'LEVEL_INVALID_KEY', name + ' - correct error code (callback)')
|
||||
}))
|
||||
|
||||
db.del(key).catch(function (err) {
|
||||
t.ok(err instanceof Error, name + ' - is Error (promise)')
|
||||
t.is(err.code, 'LEVEL_INVALID_KEY', name + ' - correct error code (callback)')
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
exports.del = function (test, testCommon) {
|
||||
test('test simple del()', function (t) {
|
||||
db.put('foo', 'bar', function (err) {
|
||||
t.error(err)
|
||||
db.del('foo', function (err) {
|
||||
t.error(err)
|
||||
db.get('foo', function (err, value) {
|
||||
t.ok(err, 'entry properly deleted')
|
||||
t.ok(typeof value === 'undefined', 'value is undefined')
|
||||
t.ok(verifyNotFoundError(err), 'NotFound error')
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('test simple del() with promise', function (t) {
|
||||
db.put('foo', 'bar', function (err) {
|
||||
t.error(err)
|
||||
db.del('foo').then(function (err) {
|
||||
t.error(err)
|
||||
db.get('foo', function (err, value) {
|
||||
t.ok(err, 'entry properly deleted')
|
||||
t.ok(typeof value === 'undefined', 'value is undefined')
|
||||
t.ok(verifyNotFoundError(err), 'NotFound error')
|
||||
t.end()
|
||||
})
|
||||
}).catch(t.fail.bind(t))
|
||||
})
|
||||
})
|
||||
|
||||
test('test del on non-existent key', function (t) {
|
||||
db.del('blargh', function (err) {
|
||||
t.error(err)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
test('test del on non-existent key, with promise', async function (t) {
|
||||
return db.del('blargh')
|
||||
})
|
||||
}
|
||||
|
||||
exports.events = function (test, testCommon) {
|
||||
test('test del() emits del event', async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
|
||||
t.ok(db.supports.events.del)
|
||||
|
||||
db.on('del', function (key) {
|
||||
t.is(key, 456)
|
||||
})
|
||||
|
||||
await db.del(456)
|
||||
await db.close()
|
||||
})
|
||||
}
|
||||
|
||||
exports.tearDown = function (test, testCommon) {
|
||||
test('tearDown', function (t) {
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.setUp(test, testCommon)
|
||||
exports.args(test, testCommon)
|
||||
exports.del(test, testCommon)
|
||||
exports.events(test, testCommon)
|
||||
exports.tearDown(test, testCommon)
|
||||
}
|
255
node_modules/abstract-level/test/encoding-buffer-test.js
generated
vendored
Normal file
255
node_modules/abstract-level/test/encoding-buffer-test.js
generated
vendored
Normal file
@ -0,0 +1,255 @@
|
||||
'use strict'
|
||||
|
||||
const { Buffer } = require('buffer')
|
||||
const textEncoder = new TextEncoder()
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
if (!testCommon.supports.encodings.buffer) return
|
||||
|
||||
// NOTE: adapted from levelup
|
||||
test('test put() and get() with buffer value and buffer valueEncoding', async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
await db.put('test', testBuffer(), { valueEncoding: 'buffer' })
|
||||
t.same(await db.get('test', { valueEncoding: 'buffer' }), testBuffer())
|
||||
return db.close()
|
||||
})
|
||||
|
||||
// NOTE: adapted from levelup
|
||||
test('test put() and get() with buffer value and buffer valueEncoding in factory', async function (t) {
|
||||
const db = testCommon.factory({ valueEncoding: 'buffer' })
|
||||
await db.open()
|
||||
await db.put('test', testBuffer())
|
||||
t.same(await db.get('test'), testBuffer())
|
||||
return db.close()
|
||||
})
|
||||
|
||||
// NOTE: adapted from levelup
|
||||
test('test put() and get() with buffer key and buffer keyEncoding', async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
await db.put(testBuffer(), 'test', { keyEncoding: 'buffer' })
|
||||
t.same(await db.get(testBuffer(), { keyEncoding: 'buffer' }), 'test')
|
||||
return db.close()
|
||||
})
|
||||
|
||||
// NOTE: adapted from levelup
|
||||
test('test put() and get() with buffer key and utf8 keyEncoding', async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
await db.put(Buffer.from('foo🐄'), 'test', { keyEncoding: 'utf8' })
|
||||
t.same(await db.get(Buffer.from('foo🐄'), { keyEncoding: 'utf8' }), 'test')
|
||||
return db.close()
|
||||
})
|
||||
|
||||
// NOTE: adapted from levelup
|
||||
test('test put() and get() with string value and buffer valueEncoding', async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
await db.put('test', 'foo🐄', { valueEncoding: 'buffer' })
|
||||
t.same(await db.get('test', { valueEncoding: 'buffer' }), Buffer.from('foo🐄'))
|
||||
t.same(await db.get('test', { valueEncoding: 'utf8' }), 'foo🐄')
|
||||
return db.close()
|
||||
})
|
||||
|
||||
// NOTE: adapted from memdown
|
||||
test('put() as string, get() as buffer and vice versa', async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
const enc = { keyEncoding: 'buffer', valueEncoding: 'buffer' }
|
||||
const [a, b] = ['🐄', '🐄 says moo']
|
||||
|
||||
const promise1 = db.put(a, a).then(async () => {
|
||||
const value = await db.get(Buffer.from(a), enc)
|
||||
t.same(value, Buffer.from(a), 'got buffer value')
|
||||
})
|
||||
|
||||
const promise2 = db.put(Buffer.from(b), Buffer.from(b), enc).then(async () => {
|
||||
const value = await db.get(b)
|
||||
t.same(value, b, 'got string value')
|
||||
})
|
||||
|
||||
await Promise.all([promise1, promise2])
|
||||
return db.close()
|
||||
})
|
||||
|
||||
// NOTE: adapted from memdown
|
||||
test('put() stringifies input to buffer', async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
await db.put(1, 2)
|
||||
|
||||
const it = db.iterator({ keyEncoding: 'buffer', valueEncoding: 'buffer' })
|
||||
const entries = await it.all()
|
||||
|
||||
t.same(entries[0][0], Buffer.from('1'), 'key was stringified')
|
||||
t.same(entries[0][1], Buffer.from('2'), 'value was stringified')
|
||||
|
||||
return db.close()
|
||||
})
|
||||
|
||||
// NOTE: adapted from memdown
|
||||
test('put() as string, iterate as buffer', async function (t) {
|
||||
const db = testCommon.factory({ keyEncoding: 'utf8', valueEncoding: 'utf8' })
|
||||
await db.open()
|
||||
await db.put('🐄', '🐄')
|
||||
|
||||
const it = db.iterator({ keyEncoding: 'buffer', valueEncoding: 'buffer' })
|
||||
const entries = await it.all()
|
||||
|
||||
t.same(entries, [[Buffer.from('🐄'), Buffer.from('🐄')]])
|
||||
return db.close()
|
||||
})
|
||||
|
||||
// NOTE: adapted from memdown
|
||||
test('put() as buffer, iterate as string', async function (t) {
|
||||
const db = testCommon.factory({ keyEncoding: 'buffer', valueEncoding: 'buffer' })
|
||||
await db.open()
|
||||
await db.put(Buffer.from('🐄'), Buffer.from('🐄'))
|
||||
|
||||
const it = db.iterator({ keyEncoding: 'utf8', valueEncoding: 'utf8' })
|
||||
const entries = await it.all()
|
||||
|
||||
t.same(entries, [['🐄', '🐄']])
|
||||
return db.close()
|
||||
})
|
||||
|
||||
test('put() as view, iterate as view', async function (t) {
|
||||
const db = testCommon.factory({ keyEncoding: 'view', valueEncoding: 'view' })
|
||||
const cow = textEncoder.encode('🐄')
|
||||
await db.open()
|
||||
await db.put(cow, cow)
|
||||
|
||||
const it = db.iterator()
|
||||
const entries = await it.all()
|
||||
const key = Buffer.isBuffer(entries[0][0]) ? Buffer.from(cow) : cow // Valid, Buffer is a Uint8Array
|
||||
const value = Buffer.isBuffer(entries[0][1]) ? Buffer.from(cow) : cow
|
||||
|
||||
t.same(entries, [[key, value]])
|
||||
return db.close()
|
||||
})
|
||||
|
||||
test('put() as string, iterate as view', async function (t) {
|
||||
const db = testCommon.factory({ keyEncoding: 'utf8', valueEncoding: 'utf8' })
|
||||
const cow = textEncoder.encode('🐄')
|
||||
await db.open()
|
||||
await db.put('🐄', '🐄')
|
||||
|
||||
const it = db.iterator({ keyEncoding: 'view', valueEncoding: 'view' })
|
||||
const entries = await it.all()
|
||||
const key = Buffer.isBuffer(entries[0][0]) ? Buffer.from(cow) : cow // Valid, Buffer is a Uint8Array
|
||||
const value = Buffer.isBuffer(entries[0][1]) ? Buffer.from(cow) : cow
|
||||
|
||||
t.same(entries, [[key, value]])
|
||||
return db.close()
|
||||
})
|
||||
|
||||
test('put() as view, iterate as string', async function (t) {
|
||||
const db = testCommon.factory({ keyEncoding: 'view', valueEncoding: 'view' })
|
||||
const cow = textEncoder.encode('🐄')
|
||||
await db.open()
|
||||
await db.put(cow, cow)
|
||||
|
||||
const it = db.iterator({ keyEncoding: 'utf8', valueEncoding: 'utf8' })
|
||||
const entries = await it.all()
|
||||
|
||||
t.same(entries, [['🐄', '🐄']])
|
||||
return db.close()
|
||||
})
|
||||
|
||||
// NOTE: adapted from levelup
|
||||
test('batch() with multiple puts with buffer valueEncoding per batch', async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
await db.batch([
|
||||
{ type: 'put', key: 'foo', value: testBuffer() },
|
||||
{ type: 'put', key: 'bar', value: testBuffer() },
|
||||
{ type: 'put', key: 'baz', value: 'abazvalue' }
|
||||
], { valueEncoding: 'buffer' })
|
||||
|
||||
t.same(await db.get('foo', { valueEncoding: 'buffer' }), testBuffer())
|
||||
t.same(await db.get('bar', { valueEncoding: 'buffer' }), testBuffer())
|
||||
t.same(await db.get('baz', { valueEncoding: 'buffer' }), Buffer.from('abazvalue'))
|
||||
|
||||
return db.close()
|
||||
})
|
||||
|
||||
test('batch() with multiple puts with buffer valueEncoding per operation', async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
await db.batch([
|
||||
{ type: 'put', key: 'foo', value: testBuffer(), valueEncoding: 'buffer' },
|
||||
{ type: 'put', key: 'bar', value: testBuffer(), valueEncoding: 'buffer' },
|
||||
{ type: 'put', key: 'baz', value: 'abazvalue', valueEncoding: 'buffer' }
|
||||
])
|
||||
|
||||
t.same(await db.get('foo', { valueEncoding: 'buffer' }), testBuffer())
|
||||
t.same(await db.get('bar', { valueEncoding: 'buffer' }), testBuffer())
|
||||
t.same(await db.get('baz', { valueEncoding: 'buffer' }), Buffer.from('abazvalue'))
|
||||
|
||||
return db.close()
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test('batch() with buffer encoding in factory', async function (t) {
|
||||
const operations = [{
|
||||
type: 'put',
|
||||
key: Buffer.from([1, 2, 3]),
|
||||
value: Buffer.from([4, 5, 6])
|
||||
}, {
|
||||
type: 'put',
|
||||
key: Buffer.from([7, 8, 9]),
|
||||
value: Buffer.from([10, 11, 12])
|
||||
}]
|
||||
|
||||
const db = testCommon.factory({ keyEncoding: 'buffer', valueEncoding: 'buffer' })
|
||||
await db.open()
|
||||
await db.batch(operations)
|
||||
|
||||
t.same(await db.get(operations[0].key), operations[0].value)
|
||||
t.same(await db.get(operations[1].key), operations[1].value)
|
||||
|
||||
return db.close()
|
||||
})
|
||||
|
||||
for (const keyEncoding of ['buffer', 'view']) {
|
||||
// NOTE: adapted from memdown
|
||||
test(`storage is byte-aware (${keyEncoding} encoding)`, function (t) {
|
||||
const db = testCommon.factory({ keyEncoding })
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open error')
|
||||
|
||||
const one = Buffer.from('80', 'hex')
|
||||
const two = Buffer.from('c0', 'hex')
|
||||
|
||||
t.ok(two.toString() === one.toString(), 'would be equal when not byte-aware')
|
||||
t.ok(two.compare(one) > 0, 'but greater when byte-aware')
|
||||
|
||||
db.put(one, 'one', function (err) {
|
||||
t.ifError(err, 'no put() error')
|
||||
|
||||
db.get(one, function (err, value) {
|
||||
t.ifError(err, 'no get() error')
|
||||
t.is(value, 'one', 'value one ok')
|
||||
|
||||
db.put(two, 'two', function (err) {
|
||||
t.ifError(err, 'no put() error')
|
||||
|
||||
db.get(one, function (err, value) {
|
||||
t.ifError(err, 'no get() error')
|
||||
t.is(value, 'one', 'value one did not change')
|
||||
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function testBuffer () {
|
||||
return Buffer.from('0080c0ff', 'hex')
|
||||
}
|
99
node_modules/abstract-level/test/encoding-custom-test.js
generated
vendored
Normal file
99
node_modules/abstract-level/test/encoding-custom-test.js
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
'use strict'
|
||||
|
||||
// NOTE: copied from levelup
|
||||
exports.all = function (test, testCommon) {
|
||||
for (const deferred of [false, true]) {
|
||||
test(`custom encoding: simple-object values (deferred: ${deferred})`, function (t) {
|
||||
run(t, deferred, [
|
||||
{ key: '0', value: 0 },
|
||||
{ key: '1', value: 1 },
|
||||
{ key: 'string', value: 'a string' },
|
||||
{ key: 'true', value: true },
|
||||
{ key: 'false', value: false }
|
||||
])
|
||||
})
|
||||
|
||||
test(`custom encoding: simple-object keys (deferred: ${deferred})`, function (t) {
|
||||
// Test keys that would be considered the same with default utf8 encoding.
|
||||
// Because String([1]) === String(1).
|
||||
run(t, deferred, [
|
||||
{ value: '0', key: [1] },
|
||||
{ value: '1', key: 1 },
|
||||
{ value: 'string', key: 'a string' },
|
||||
{ value: 'true', key: true },
|
||||
{ value: 'false', key: false }
|
||||
])
|
||||
})
|
||||
|
||||
test(`custom encoding: complex-object values (deferred: ${deferred})`, function (t) {
|
||||
run(t, deferred, [{
|
||||
key: '0',
|
||||
value: {
|
||||
foo: 'bar',
|
||||
bar: [1, 2, 3],
|
||||
bang: { yes: true, no: false }
|
||||
}
|
||||
}])
|
||||
})
|
||||
|
||||
test(`custom encoding: complex-object keys (deferred: ${deferred})`, function (t) {
|
||||
// Test keys that would be considered the same with default utf8 encoding.
|
||||
// Because String({}) === String({}) === '[object Object]'.
|
||||
run(t, deferred, [{
|
||||
value: '0',
|
||||
key: {
|
||||
foo: 'bar',
|
||||
bar: [1, 2, 3],
|
||||
bang: { yes: true, no: false }
|
||||
}
|
||||
}, {
|
||||
value: '1',
|
||||
key: {
|
||||
foo: 'different',
|
||||
bar: [1, 2, 3],
|
||||
bang: { yes: true, no: false }
|
||||
}
|
||||
}])
|
||||
})
|
||||
}
|
||||
|
||||
function run (t, deferred, entries) {
|
||||
const customEncoding = {
|
||||
encode: JSON.stringify,
|
||||
decode: JSON.parse,
|
||||
format: 'utf8',
|
||||
type: 'custom'
|
||||
}
|
||||
|
||||
const db = testCommon.factory({
|
||||
keyEncoding: customEncoding,
|
||||
valueEncoding: customEncoding
|
||||
})
|
||||
|
||||
const operations = entries.map(entry => ({ type: 'put', ...entry }))
|
||||
const init = deferred ? (fn) => fn() : db.open.bind(db)
|
||||
|
||||
init(function (err) {
|
||||
t.ifError(err, 'no init() error')
|
||||
|
||||
db.batch(operations, function (err) {
|
||||
t.ifError(err, 'no batch() error')
|
||||
|
||||
let pending = entries.length
|
||||
const next = () => {
|
||||
if (--pending === 0) {
|
||||
db.close(t.end.bind(t))
|
||||
}
|
||||
}
|
||||
|
||||
for (const entry of entries) {
|
||||
db.get(entry.key, function (err, value) {
|
||||
t.ifError(err, 'no get() error')
|
||||
t.same(value, entry.value)
|
||||
next()
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
64
node_modules/abstract-level/test/encoding-decode-error-test.js
generated
vendored
Normal file
64
node_modules/abstract-level/test/encoding-decode-error-test.js
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
'use strict'
|
||||
|
||||
let db
|
||||
let keySequence = 0
|
||||
|
||||
const testKey = () => 'test' + (++keySequence)
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
test('setup', async function (t) {
|
||||
db = testCommon.factory()
|
||||
return db.open()
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test('get() and getMany() forward decode error', function (t) {
|
||||
const key = testKey()
|
||||
const valueEncoding = {
|
||||
encode: (v) => v,
|
||||
decode: (v) => { throw new Error('decode error xyz') },
|
||||
format: 'utf8'
|
||||
}
|
||||
|
||||
db.put(key, 'bar', { valueEncoding }, function (err) {
|
||||
t.ifError(err, 'no put() error')
|
||||
|
||||
db.get(key, { valueEncoding }, function (err, value) {
|
||||
t.is(err && err.code, 'LEVEL_DECODE_ERROR')
|
||||
t.is(err && err.cause && err.cause.message, 'decode error xyz')
|
||||
t.is(value, undefined)
|
||||
|
||||
db.getMany(['other-key', key], { valueEncoding }, function (err, values) {
|
||||
t.is(err && err.code, 'LEVEL_DECODE_ERROR')
|
||||
t.is(err && err.cause && err.cause.message, 'decode error xyz')
|
||||
t.is(values, undefined)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test('get() and getMany() yield encoding error if stored value is invalid', function (t) {
|
||||
const key = testKey()
|
||||
|
||||
db.put(key, 'this {} is [] not : json', { valueEncoding: 'utf8' }, function (err) {
|
||||
t.ifError(err, 'no put() error')
|
||||
|
||||
db.get(key, { valueEncoding: 'json' }, function (err) {
|
||||
t.is(err && err.code, 'LEVEL_DECODE_ERROR')
|
||||
t.is(err && err.cause.name, 'SyntaxError') // From JSON.parse()
|
||||
|
||||
db.getMany(['other-key', key], { valueEncoding: 'json' }, function (err) {
|
||||
t.is(err && err.code, 'LEVEL_DECODE_ERROR')
|
||||
t.is(err && err.cause.name, 'SyntaxError') // From JSON.parse()
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('teardown', async function (t) {
|
||||
return db.close()
|
||||
})
|
||||
}
|
88
node_modules/abstract-level/test/encoding-json-test.js
generated
vendored
Normal file
88
node_modules/abstract-level/test/encoding-json-test.js
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
'use strict'
|
||||
|
||||
// NOTE: copied from levelup
|
||||
exports.all = function (test, testCommon) {
|
||||
for (const deferred of [false, true]) {
|
||||
test(`json encoding: simple-object values (deferred: ${deferred})`, function (t) {
|
||||
run(t, deferred, [
|
||||
{ key: '0', value: 0 },
|
||||
{ key: '1', value: 1 },
|
||||
{ key: '2', value: 'a string' },
|
||||
{ key: '3', value: true },
|
||||
{ key: '4', value: false }
|
||||
])
|
||||
})
|
||||
|
||||
test(`json encoding: simple-object keys (deferred: ${deferred})`, function (t) {
|
||||
run(t, deferred, [
|
||||
{ value: 'string', key: 'a string' },
|
||||
{ value: '0', key: 0 },
|
||||
{ value: '1', key: 1 },
|
||||
{ value: 'false', key: false },
|
||||
{ value: 'true', key: true }
|
||||
])
|
||||
})
|
||||
|
||||
test(`json encoding: complex-object values (deferred: ${deferred})`, function (t) {
|
||||
run(t, deferred, [{
|
||||
key: '0',
|
||||
value: {
|
||||
foo: 'bar',
|
||||
bar: [1, 2, 3],
|
||||
bang: { yes: true, no: false }
|
||||
}
|
||||
}])
|
||||
})
|
||||
|
||||
test(`json encoding: complex-object keys (deferred: ${deferred})`, function (t) {
|
||||
run(t, deferred, [{
|
||||
value: '0',
|
||||
key: {
|
||||
foo: 'bar',
|
||||
bar: [1, 2, 3],
|
||||
bang: { yes: true, no: false }
|
||||
}
|
||||
}])
|
||||
})
|
||||
}
|
||||
|
||||
function run (t, deferred, entries) {
|
||||
const db = testCommon.factory({ keyEncoding: 'json', valueEncoding: 'json' })
|
||||
const operations = entries.map(entry => ({ type: 'put', ...entry }))
|
||||
const init = deferred ? (fn) => fn() : db.open.bind(db)
|
||||
|
||||
init(function (err) {
|
||||
t.ifError(err, 'no init() error')
|
||||
|
||||
db.batch(operations, function (err) {
|
||||
t.ifError(err, 'no batch() error')
|
||||
|
||||
let pending = entries.length + 1
|
||||
const next = () => {
|
||||
if (--pending === 0) db.close(t.end.bind(t))
|
||||
}
|
||||
|
||||
testGet(next)
|
||||
testIterator(next)
|
||||
})
|
||||
})
|
||||
|
||||
function testGet (next) {
|
||||
for (const entry of entries) {
|
||||
db.get(entry.key, function (err, value) {
|
||||
t.ifError(err, 'no get() error')
|
||||
t.same(value, entry.value)
|
||||
next()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function testIterator (next) {
|
||||
db.iterator().all(function (err, result) {
|
||||
t.ifError(err, 'no all() error')
|
||||
t.same(result, entries.map(kv => [kv.key, kv.value]))
|
||||
next()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
141
node_modules/abstract-level/test/encoding-test.js
generated
vendored
Normal file
141
node_modules/abstract-level/test/encoding-test.js
generated
vendored
Normal file
@ -0,0 +1,141 @@
|
||||
'use strict'
|
||||
|
||||
let db
|
||||
let keySequence = 0
|
||||
|
||||
const testKey = () => 'test' + (++keySequence)
|
||||
|
||||
// TODO: test encoding options on every method. This is largely
|
||||
// covered (indirectly) by other tests, but a dedicated property-
|
||||
// based test for each would be good to have.
|
||||
exports.all = function (test, testCommon) {
|
||||
test('setup', async function (t) {
|
||||
db = testCommon.factory()
|
||||
return db.open()
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test('encodings default to utf8', function (t) {
|
||||
t.is(db.keyEncoding().commonName, 'utf8')
|
||||
t.is(db.valueEncoding().commonName, 'utf8')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('can set encoding options in factory', async function (t) {
|
||||
const dbs = []
|
||||
|
||||
for (const name of ['buffer', 'view', 'json']) {
|
||||
if (!testCommon.supports.encodings[name]) continue
|
||||
|
||||
const db1 = testCommon.factory({ keyEncoding: name })
|
||||
const db2 = testCommon.factory({ valueEncoding: name })
|
||||
const db3 = testCommon.factory({ keyEncoding: name, valueEncoding: name })
|
||||
|
||||
t.is(db1.keyEncoding().commonName, name)
|
||||
t.is(db1.keyEncoding(), db1.keyEncoding(name))
|
||||
t.is(db1.valueEncoding().commonName, 'utf8')
|
||||
t.is(db1.valueEncoding(), db1.valueEncoding('utf8'))
|
||||
|
||||
t.is(db2.keyEncoding().commonName, 'utf8')
|
||||
t.is(db2.keyEncoding(), db2.keyEncoding('utf8'))
|
||||
t.is(db2.valueEncoding().commonName, name)
|
||||
t.is(db2.valueEncoding(), db2.valueEncoding(name))
|
||||
|
||||
t.is(db3.keyEncoding().commonName, name)
|
||||
t.is(db3.keyEncoding(), db3.keyEncoding(name))
|
||||
t.is(db3.valueEncoding().commonName, name)
|
||||
t.is(db3.valueEncoding(), db3.valueEncoding(name))
|
||||
|
||||
dbs.push(db1, db2, db3)
|
||||
}
|
||||
|
||||
await Promise.all(dbs.map(db => db.close()))
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
for (const deferred of [false, true]) {
|
||||
test(`default utf8 encoding stringifies numbers (deferred: ${deferred})`, async function (t) {
|
||||
const db = testCommon.factory()
|
||||
if (!deferred) await db.open()
|
||||
await db.put(1, 2)
|
||||
t.is(await db.get(1), '2')
|
||||
return db.close()
|
||||
})
|
||||
}
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test('can decode from string to json', function (t) {
|
||||
const key = testKey()
|
||||
const data = { thisis: 'json' }
|
||||
|
||||
db.put(key, JSON.stringify(data), { valueEncoding: 'utf8' }, function (err) {
|
||||
t.ifError(err, 'no put() error')
|
||||
|
||||
db.get(key, { valueEncoding: 'json' }, function (err, value) {
|
||||
t.ifError(err, 'no get() error')
|
||||
t.same(value, data, 'got parsed object')
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test('can decode from json to string', function (t) {
|
||||
const data = { thisis: 'json' }
|
||||
const key = testKey()
|
||||
|
||||
db.put(key, data, { valueEncoding: 'json' }, function (err) {
|
||||
t.ifError(err, 'no put() error')
|
||||
|
||||
db.get(key, { valueEncoding: 'utf8' }, function (err, value) {
|
||||
t.ifError(err, 'no get() error')
|
||||
t.is(value, JSON.stringify(data), 'got unparsed JSON string')
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test('getMany() skips decoding not-found values', function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const valueEncoding = {
|
||||
encode: JSON.stringify,
|
||||
decode (value) {
|
||||
t.is(value, JSON.stringify(data))
|
||||
return JSON.parse(value)
|
||||
},
|
||||
format: 'utf8'
|
||||
}
|
||||
|
||||
const data = { beep: 'boop' }
|
||||
const key = testKey()
|
||||
|
||||
db.put(key, data, { valueEncoding }, function (err) {
|
||||
t.ifError(err, 'no put() error')
|
||||
|
||||
db.getMany([key, testKey()], { valueEncoding }, function (err, values) {
|
||||
t.ifError(err, 'no getMany() error')
|
||||
t.same(values, [data, undefined])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// NOTE: adapted from memdown
|
||||
test('number keys with utf8 encoding', async function (t) {
|
||||
const db = testCommon.factory()
|
||||
const numbers = [-Infinity, 0, 12, 2, +Infinity]
|
||||
|
||||
await db.open()
|
||||
await db.batch(numbers.map(key => ({ type: 'put', key, value: 'value' })))
|
||||
|
||||
const keys = await db.keys({ keyEncoding: 'utf8' }).all()
|
||||
t.same(keys, numbers.map(String), 'sorts lexicographically')
|
||||
|
||||
return db.close()
|
||||
})
|
||||
|
||||
test('teardown', async function (t) {
|
||||
return db.close()
|
||||
})
|
||||
}
|
52
node_modules/abstract-level/test/factory-test.js
generated
vendored
Normal file
52
node_modules/abstract-level/test/factory-test.js
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = function (test, testCommon) {
|
||||
test('testCommon.factory() returns valid database', function (t) {
|
||||
t.plan(6)
|
||||
|
||||
const db = testCommon.factory()
|
||||
const kEvent = Symbol('event')
|
||||
|
||||
// Avoid instanceof, for levelup compatibility tests
|
||||
t.is(typeof db, 'object', 'is an object')
|
||||
t.isNot(db, null, 'is not null')
|
||||
t.is(typeof db.open, 'function', 'has open() method')
|
||||
t.is(typeof db.on, 'function', 'has on() method')
|
||||
t.is(typeof db.emit, 'function', 'has emit() method')
|
||||
|
||||
db.once(kEvent, (v) => t.is(v, 'foo', 'got event'))
|
||||
db.emit(kEvent, 'foo')
|
||||
})
|
||||
|
||||
test('testCommon.factory() returns a unique database', function (t) {
|
||||
const db1 = testCommon.factory()
|
||||
const db2 = testCommon.factory()
|
||||
|
||||
t.isNot(db1, db2, 'unique instances')
|
||||
|
||||
function close () {
|
||||
db1.close(function (err) {
|
||||
t.error(err, 'no error while closing db1')
|
||||
db2.close(function (err) {
|
||||
t.error(err, 'no error while closing db2')
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
db1.open(function (err) {
|
||||
t.error(err, 'no error while opening db1')
|
||||
db2.open(function (err) {
|
||||
t.error(err, 'no error while opening db2')
|
||||
db1.put('key', 'value', function (err) {
|
||||
t.error(err, 'put key in db1')
|
||||
db2.get('key', function (err, value) {
|
||||
t.ok(err, 'db2 should be empty')
|
||||
t.is(value, undefined, 'db2 should be empty')
|
||||
close()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
276
node_modules/abstract-level/test/get-many-test.js
generated
vendored
Normal file
276
node_modules/abstract-level/test/get-many-test.js
generated
vendored
Normal file
@ -0,0 +1,276 @@
|
||||
'use strict'
|
||||
|
||||
const { assertAsync, illegalKeys } = require('./util')
|
||||
|
||||
let db
|
||||
|
||||
/**
|
||||
* @param {import('tape')} test
|
||||
*/
|
||||
exports.setUp = function (test, testCommon) {
|
||||
test('setUp db', function (t) {
|
||||
db = testCommon.factory()
|
||||
db.open(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('tape')} test
|
||||
*/
|
||||
exports.args = function (test, testCommon) {
|
||||
test('test getMany() requires an array argument (callback)', assertAsync.ctx(function (t) {
|
||||
// Add 1 assertion for every assertAsync()
|
||||
t.plan(6)
|
||||
|
||||
db.getMany('foo', assertAsync(function (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err && err.message, "The first argument 'keys' must be an array")
|
||||
}))
|
||||
db.getMany('foo', {}, assertAsync(function (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err && err.message, "The first argument 'keys' must be an array")
|
||||
}))
|
||||
}))
|
||||
|
||||
test('test getMany() requires an array argument (promise)', function (t) {
|
||||
t.plan(6)
|
||||
|
||||
db.getMany().catch(function (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err && err.message, "The first argument 'keys' must be an array")
|
||||
})
|
||||
db.getMany('foo').catch(function (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err && err.message, "The first argument 'keys' must be an array")
|
||||
})
|
||||
db.getMany('foo', {}).catch(function (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err && err.message, "The first argument 'keys' must be an array")
|
||||
})
|
||||
})
|
||||
|
||||
test('test getMany() with illegal keys', assertAsync.ctx(function (t) {
|
||||
// Add 1 assertion for every assertAsync()
|
||||
t.plan(illegalKeys.length * 10)
|
||||
|
||||
for (const { name, key } of illegalKeys) {
|
||||
db.getMany([key], assertAsync(function (err) {
|
||||
t.ok(err instanceof Error, name + ' - is Error (callback)')
|
||||
t.is(err && err.code, 'LEVEL_INVALID_KEY', name + ' - correct error code (callback)')
|
||||
}))
|
||||
|
||||
db.getMany(['valid', key], assertAsync(function (err) {
|
||||
t.ok(err instanceof Error, name + ' - is Error (callback, second key)')
|
||||
t.is(err && err.code, 'LEVEL_INVALID_KEY', name + ' - correct error code (callback, second key)')
|
||||
}))
|
||||
|
||||
db.getMany([key]).catch(function (err) {
|
||||
t.ok(err instanceof Error, name + ' - is Error (promise)')
|
||||
t.is(err.code, 'LEVEL_INVALID_KEY', name + ' - correct error code (promise)')
|
||||
})
|
||||
|
||||
db.getMany(['valid', key]).catch(function (err) {
|
||||
t.ok(err instanceof Error, name + ' - is Error (promise, second key)')
|
||||
t.is(err.code, 'LEVEL_INVALID_KEY', name + ' - correct error code (promise, second key)')
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('tape')} test
|
||||
*/
|
||||
exports.getMany = function (test, testCommon) {
|
||||
test('test simple getMany()', function (t) {
|
||||
db.put('foo', 'bar', function (err) {
|
||||
t.error(err)
|
||||
|
||||
function verify (err, values) {
|
||||
t.error(err)
|
||||
t.ok(Array.isArray(values), 'got an array')
|
||||
t.is(values.length, 1, 'array has 1 element')
|
||||
t.is(values[0], 'bar')
|
||||
}
|
||||
|
||||
db.getMany(['foo'], function (err, values) {
|
||||
verify(err, values)
|
||||
|
||||
db.getMany(['foo'], {}, function (err, values) {
|
||||
verify(err, values)
|
||||
|
||||
db.getMany(['foo'], { valueEncoding: 'utf8' }, function (err, values) {
|
||||
t.error(err)
|
||||
t.is(values && typeof values[0], 'string', 'should be string if not buffer')
|
||||
t.same(values, ['bar'])
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('test getMany() with multiple keys', function (t) {
|
||||
t.plan(5)
|
||||
|
||||
db.put('beep', 'boop', function (err) {
|
||||
t.ifError(err)
|
||||
|
||||
db.getMany(['foo', 'beep'], { valueEncoding: 'utf8' }, function (err, values) {
|
||||
t.ifError(err)
|
||||
t.same(values, ['bar', 'boop'])
|
||||
})
|
||||
|
||||
db.getMany(['beep', 'foo'], { valueEncoding: 'utf8' }, function (err, values) {
|
||||
t.ifError(err)
|
||||
t.same(values, ['boop', 'bar'], 'maintains order of input keys')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('test empty getMany()', assertAsync.ctx(function (t) {
|
||||
const encodings = Object.keys(db.supports.encodings).filter(k => db.supports.encodings[k])
|
||||
t.plan(encodings.length * 3)
|
||||
|
||||
for (const valueEncoding of encodings) {
|
||||
db.getMany([], { valueEncoding }, assertAsync(function (err, values) {
|
||||
t.ifError(err)
|
||||
t.same(values, [])
|
||||
}))
|
||||
}
|
||||
}))
|
||||
|
||||
test('test not-found getMany()', assertAsync.ctx(function (t) {
|
||||
const encodings = Object.keys(db.supports.encodings).filter(k => db.supports.encodings[k])
|
||||
t.plan(encodings.length * 3)
|
||||
|
||||
for (const valueEncoding of encodings) {
|
||||
db.getMany(['nope', 'another'], { valueEncoding }, assertAsync(function (err, values) {
|
||||
t.ifError(err)
|
||||
t.same(values, [undefined, undefined])
|
||||
}))
|
||||
}
|
||||
}))
|
||||
|
||||
test('test getMany() with promise', async function (t) {
|
||||
t.same(await db.getMany(['foo'], { valueEncoding: 'utf8' }), ['bar'])
|
||||
t.same(await db.getMany(['beep'], { valueEncoding: 'utf8' }), ['boop'])
|
||||
t.same(await db.getMany(['foo', 'beep'], { valueEncoding: 'utf8' }), ['bar', 'boop'])
|
||||
t.same(await db.getMany(['beep', 'foo'], { valueEncoding: 'utf8' }), ['boop', 'bar'])
|
||||
t.same(await db.getMany(['beep', 'foo', 'nope'], { valueEncoding: 'utf8' }), ['boop', 'bar', undefined])
|
||||
t.same(await db.getMany([], { valueEncoding: 'utf8' }), [])
|
||||
})
|
||||
|
||||
test('test simultaneous getMany()', function (t) {
|
||||
db.put('hello', 'world', function (err) {
|
||||
t.error(err)
|
||||
|
||||
let completed = 0
|
||||
const done = function () {
|
||||
if (++completed === 20) t.end()
|
||||
}
|
||||
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
db.getMany(['hello'], function (err, values) {
|
||||
t.error(err)
|
||||
t.is(values.length, 1)
|
||||
t.is(values[0] && values[0].toString(), 'world')
|
||||
done()
|
||||
})
|
||||
}
|
||||
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
db.getMany(['not found'], function (err, values) {
|
||||
t.error(err)
|
||||
t.same(values, [undefined])
|
||||
done()
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('test getMany() on opening db', assertAsync.ctx(function (t) {
|
||||
t.plan(2 * 2 * 5)
|
||||
|
||||
// Also test empty array because it has a fast-path
|
||||
for (const keys of [['foo'], []]) {
|
||||
// Opening should make no difference, because we call it after getMany()
|
||||
for (const open of [true, false]) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
t.is(db.status, 'opening')
|
||||
|
||||
db.getMany(keys, assertAsync(function (err, values) {
|
||||
t.ifError(err, 'no error')
|
||||
t.same(values, keys.map(_ => undefined))
|
||||
}))
|
||||
|
||||
if (open) {
|
||||
db.open(t.error.bind(t))
|
||||
} else {
|
||||
t.pass()
|
||||
}
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
test('test getMany() on closed db', function (t) {
|
||||
t.plan(2 * 4)
|
||||
|
||||
// Also test empty array because it has a fast-path
|
||||
for (const keys of [['foo'], []]) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err)
|
||||
|
||||
db.close(assertAsync.with(t, function (err) {
|
||||
t.ifError(err)
|
||||
|
||||
db.getMany(keys, assertAsync(function (err) {
|
||||
t.is(err && err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
}))
|
||||
}))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('test getMany() on closing db', function (t) {
|
||||
t.plan(2 * 4)
|
||||
|
||||
// Also test empty array because it has a fast-path
|
||||
for (const keys of [['foo'], []]) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(assertAsync.with(t, function (err) {
|
||||
t.ifError(err)
|
||||
|
||||
db.close(function (err) {
|
||||
t.ifError(err)
|
||||
})
|
||||
|
||||
db.getMany(keys, assertAsync(function (err) {
|
||||
t.is(err && err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
}))
|
||||
}))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('tape')} test
|
||||
*/
|
||||
exports.tearDown = function (test, testCommon) {
|
||||
test('tearDown', function (t) {
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('tape')} test
|
||||
*/
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.setUp(test, testCommon)
|
||||
exports.args(test, testCommon)
|
||||
exports.getMany(test, testCommon)
|
||||
exports.tearDown(test, testCommon)
|
||||
}
|
144
node_modules/abstract-level/test/get-test.js
generated
vendored
Normal file
144
node_modules/abstract-level/test/get-test.js
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
'use strict'
|
||||
|
||||
const isBuffer = require('is-buffer')
|
||||
const { verifyNotFoundError, illegalKeys, assertAsync } = require('./util')
|
||||
|
||||
let db
|
||||
|
||||
exports.setUp = function (test, testCommon) {
|
||||
test('setUp db', function (t) {
|
||||
db = testCommon.factory()
|
||||
db.open(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.args = function (test, testCommon) {
|
||||
test('test get() with illegal keys', assertAsync.ctx(function (t) {
|
||||
t.plan(illegalKeys.length * 5)
|
||||
|
||||
for (const { name, key } of illegalKeys) {
|
||||
db.get(key, assertAsync(function (err) {
|
||||
t.ok(err instanceof Error, name + ' - is Error (callback)')
|
||||
t.is(err && err.code, 'LEVEL_INVALID_KEY', name + ' - correct error code (callback)')
|
||||
}))
|
||||
|
||||
db.get(key).catch(function (err) {
|
||||
t.ok(err instanceof Error, name + ' - is Error (promise)')
|
||||
t.is(err.code, 'LEVEL_INVALID_KEY', name + ' - correct error code (promise)')
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
exports.get = function (test, testCommon) {
|
||||
test('test simple get()', function (t) {
|
||||
db.put('foo', 'bar', function (err) {
|
||||
t.error(err)
|
||||
db.get('foo', function (err, value) {
|
||||
t.error(err)
|
||||
t.is(value, 'bar')
|
||||
|
||||
db.get('foo', {}, function (err, value) { // same but with {}
|
||||
t.error(err)
|
||||
t.is(value, 'bar')
|
||||
|
||||
db.get('foo', { valueEncoding: 'utf8' }, function (err, value) {
|
||||
t.error(err)
|
||||
t.is(value, 'bar')
|
||||
|
||||
if (!db.supports.encodings.buffer) {
|
||||
return t.end()
|
||||
}
|
||||
|
||||
db.get('foo', { valueEncoding: 'buffer' }, function (err, value) {
|
||||
t.error(err)
|
||||
t.ok(isBuffer(value), 'should be buffer')
|
||||
t.is(value.toString(), 'bar')
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('test get() with promise', function (t) {
|
||||
db.put('promises', 'yes', function (err) {
|
||||
t.error(err)
|
||||
|
||||
db.get('promises').then(function (value) {
|
||||
t.is(value, 'yes', 'got value without options')
|
||||
|
||||
db.get('not found').catch(function (err) {
|
||||
t.ok(err, 'should error')
|
||||
t.ok(verifyNotFoundError(err), 'correct error')
|
||||
|
||||
if (!db.supports.encodings.buffer) {
|
||||
return t.end()
|
||||
}
|
||||
|
||||
db.get('promises', { valueEncoding: 'buffer' }).then(function (value) {
|
||||
t.ok(isBuffer(value), 'is buffer')
|
||||
t.is(value.toString(), 'yes', 'correct value')
|
||||
t.end()
|
||||
}).catch(t.fail.bind(t))
|
||||
})
|
||||
}).catch(t.fail.bind(t))
|
||||
})
|
||||
})
|
||||
|
||||
test('test simultaneous get()', function (t) {
|
||||
db.put('hello', 'world', function (err) {
|
||||
t.error(err)
|
||||
let completed = 0
|
||||
const done = function () {
|
||||
if (++completed === 20) t.end()
|
||||
}
|
||||
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
db.get('hello', function (err, value) {
|
||||
t.error(err)
|
||||
t.is(value.toString(), 'world')
|
||||
done()
|
||||
})
|
||||
}
|
||||
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
db.get('not found', function (err, value) {
|
||||
t.ok(err, 'should error')
|
||||
t.ok(verifyNotFoundError(err), 'correct error')
|
||||
t.ok(typeof value === 'undefined', 'value is undefined')
|
||||
done()
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('test get() not found error is asynchronous', function (t) {
|
||||
t.plan(4)
|
||||
|
||||
let async = false
|
||||
|
||||
db.get('not found', function (err, value) {
|
||||
t.ok(err, 'should error')
|
||||
t.ok(verifyNotFoundError(err), 'correct error')
|
||||
t.ok(typeof value === 'undefined', 'value is undefined')
|
||||
t.ok(async, 'callback is asynchronous')
|
||||
})
|
||||
|
||||
async = true
|
||||
})
|
||||
}
|
||||
|
||||
exports.tearDown = function (test, testCommon) {
|
||||
test('tearDown', function (t) {
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.setUp(test, testCommon)
|
||||
exports.args(test, testCommon)
|
||||
exports.get(test, testCommon)
|
||||
exports.tearDown(test, testCommon)
|
||||
}
|
72
node_modules/abstract-level/test/index.js
generated
vendored
Normal file
72
node_modules/abstract-level/test/index.js
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
'use strict'
|
||||
|
||||
const common = require('./common')
|
||||
const kSublevels = Symbol('sublevels')
|
||||
|
||||
function suite (options) {
|
||||
const testCommon = common(options)
|
||||
const test = testCommon.test
|
||||
|
||||
require('./factory-test')(test, testCommon)
|
||||
require('./manifest-test')(test, testCommon)
|
||||
require('./open-test').all(test, testCommon)
|
||||
require('./close-test').all(test, testCommon)
|
||||
|
||||
if (testCommon.supports.createIfMissing) {
|
||||
require('./open-create-if-missing-test').all(test, testCommon)
|
||||
}
|
||||
|
||||
if (testCommon.supports.errorIfExists) {
|
||||
require('./open-error-if-exists-test').all(test, testCommon)
|
||||
}
|
||||
|
||||
require('./put-test').all(test, testCommon)
|
||||
require('./get-test').all(test, testCommon)
|
||||
require('./del-test').all(test, testCommon)
|
||||
require('./put-get-del-test').all(test, testCommon)
|
||||
require('./get-many-test').all(test, testCommon)
|
||||
|
||||
require('./batch-test').all(test, testCommon)
|
||||
require('./chained-batch-test').all(test, testCommon)
|
||||
|
||||
require('./iterator-test').all(test, testCommon)
|
||||
require('./iterator-range-test').all(test, testCommon)
|
||||
require('./async-iterator-test').all(test, testCommon)
|
||||
|
||||
require('./deferred-open-test').all(test, testCommon)
|
||||
require('./encoding-test').all(test, testCommon)
|
||||
require('./encoding-json-test').all(test, testCommon)
|
||||
require('./encoding-custom-test').all(test, testCommon)
|
||||
require('./encoding-buffer-test').all(test, testCommon)
|
||||
require('./encoding-decode-error-test').all(test, testCommon)
|
||||
|
||||
if (testCommon.supports.seek) {
|
||||
require('./iterator-seek-test').all(test, testCommon)
|
||||
}
|
||||
|
||||
if (testCommon.supports.snapshots) {
|
||||
require('./iterator-snapshot-test').all(test, testCommon)
|
||||
} else {
|
||||
require('./iterator-no-snapshot-test').all(test, testCommon)
|
||||
}
|
||||
|
||||
require('./clear-test').all(test, testCommon)
|
||||
require('./clear-range-test').all(test, testCommon)
|
||||
require('./sublevel-test').all(test, testCommon)
|
||||
|
||||
// Run the same suite on a sublevel
|
||||
if (!testCommon.internals[kSublevels]) {
|
||||
const factory = testCommon.factory
|
||||
|
||||
suite({
|
||||
...testCommon,
|
||||
internals: { [kSublevels]: true },
|
||||
factory (opts) {
|
||||
return factory().sublevel('test', opts)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
suite.common = common
|
||||
module.exports = suite
|
63
node_modules/abstract-level/test/iterator-no-snapshot-test.js
generated
vendored
Normal file
63
node_modules/abstract-level/test/iterator-no-snapshot-test.js
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
'use strict'
|
||||
|
||||
exports.noSnapshot = function (test, testCommon) {
|
||||
function make (run) {
|
||||
return function (t) {
|
||||
const db = testCommon.factory()
|
||||
const operations = [
|
||||
{ type: 'put', key: 'a', value: 'a' },
|
||||
{ type: 'put', key: 'b', value: 'b' },
|
||||
{ type: 'put', key: 'c', value: 'c' }
|
||||
]
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open error')
|
||||
|
||||
db.batch(operations, function (err) {
|
||||
t.ifError(err, 'no batch error')
|
||||
|
||||
// For this test it is important that we don't read eagerly.
|
||||
// NOTE: highWaterMarkBytes is not an abstract option, but
|
||||
// it is supported by classic-level and others. Also set the
|
||||
// old & equivalent leveldown highWaterMark option for compat.
|
||||
const it = db.iterator({ highWaterMarkBytes: 0, highWaterMark: 0 })
|
||||
|
||||
run(db, function (err) {
|
||||
t.ifError(err, 'no run error')
|
||||
verify(t, it, db)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function verify (t, it, db) {
|
||||
it.all(function (err, entries) {
|
||||
t.ifError(err, 'no iterator error')
|
||||
|
||||
const kv = entries.map(function ([key, value]) {
|
||||
return key.toString() + value.toString()
|
||||
})
|
||||
|
||||
if (kv.length === 3) {
|
||||
t.same(kv, ['aa', 'bb', 'cc'], 'maybe supports snapshots')
|
||||
} else {
|
||||
t.same(kv, ['aa', 'cc'], 'ignores keys that have been deleted in the mean time')
|
||||
}
|
||||
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
test('delete key after creating iterator', make(function (db, done) {
|
||||
db.del('b', done)
|
||||
}))
|
||||
|
||||
test('batch delete key after creating iterator', make(function (db, done) {
|
||||
db.batch([{ type: 'del', key: 'b' }], done)
|
||||
}))
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.noSnapshot(test, testCommon)
|
||||
}
|
287
node_modules/abstract-level/test/iterator-range-test.js
generated
vendored
Normal file
287
node_modules/abstract-level/test/iterator-range-test.js
generated
vendored
Normal file
@ -0,0 +1,287 @@
|
||||
'use strict'
|
||||
|
||||
let db
|
||||
|
||||
const data = (function () {
|
||||
const d = []
|
||||
let i = 0
|
||||
let k
|
||||
for (; i < 100; i++) {
|
||||
k = (i < 10 ? '0' : '') + i
|
||||
d.push({
|
||||
key: k,
|
||||
value: String(Math.random())
|
||||
})
|
||||
}
|
||||
return d
|
||||
}())
|
||||
|
||||
exports.setUp = function (test, testCommon) {
|
||||
test('setUp db', function (t) {
|
||||
db = testCommon.factory()
|
||||
db.open(function () {
|
||||
db.batch(data.map(function (d) {
|
||||
return {
|
||||
type: 'put',
|
||||
key: d.key,
|
||||
value: d.value
|
||||
}
|
||||
}), t.end.bind(t))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
exports.range = function (test, testCommon) {
|
||||
function rangeTest (name, opts, expected) {
|
||||
opts.keyEncoding = 'utf8'
|
||||
opts.valueEncoding = 'utf8'
|
||||
|
||||
test(name, function (t) {
|
||||
db.iterator(opts).all(function (err, entries) {
|
||||
t.error(err)
|
||||
t.is(entries.length, expected.length, 'correct number of entries')
|
||||
t.same(entries, expected.map(o => [o.key, o.value]))
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
// Test the documented promise that in reverse mode,
|
||||
// "the returned entries are the same, but in reverse".
|
||||
if (!opts.reverse && !('limit' in opts)) {
|
||||
const reverseOpts = Object.assign({}, opts, { reverse: true })
|
||||
|
||||
rangeTest(
|
||||
name + ' (flipped)',
|
||||
reverseOpts,
|
||||
expected.slice().reverse()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
rangeTest('test full data collection', {}, data)
|
||||
|
||||
rangeTest('test iterator with reverse=true', {
|
||||
reverse: true
|
||||
}, data.slice().reverse())
|
||||
|
||||
rangeTest('test iterator with gte=00', {
|
||||
gte: '00'
|
||||
}, data)
|
||||
|
||||
rangeTest('test iterator with gte=50', {
|
||||
gte: '50'
|
||||
}, data.slice(50))
|
||||
|
||||
rangeTest('test iterator with lte=50 and reverse=true', {
|
||||
lte: '50',
|
||||
reverse: true
|
||||
}, data.slice().reverse().slice(49))
|
||||
|
||||
rangeTest('test iterator with gte=49.5 (midway)', {
|
||||
gte: '49.5'
|
||||
}, data.slice(50))
|
||||
|
||||
rangeTest('test iterator with gte=49999 (midway)', {
|
||||
gte: '49999'
|
||||
}, data.slice(50))
|
||||
|
||||
rangeTest('test iterator with lte=49.5 (midway) and reverse=true', {
|
||||
lte: '49.5',
|
||||
reverse: true
|
||||
}, data.slice().reverse().slice(50))
|
||||
|
||||
rangeTest('test iterator with lt=49.5 (midway) and reverse=true', {
|
||||
lt: '49.5',
|
||||
reverse: true
|
||||
}, data.slice().reverse().slice(50))
|
||||
|
||||
rangeTest('test iterator with lt=50 and reverse=true', {
|
||||
lt: '50',
|
||||
reverse: true
|
||||
}, data.slice().reverse().slice(50))
|
||||
|
||||
rangeTest('test iterator with lte=50', {
|
||||
lte: '50'
|
||||
}, data.slice(0, 51))
|
||||
|
||||
rangeTest('test iterator with lte=50.5 (midway)', {
|
||||
lte: '50.5'
|
||||
}, data.slice(0, 51))
|
||||
|
||||
rangeTest('test iterator with lte=50555 (midway)', {
|
||||
lte: '50555'
|
||||
}, data.slice(0, 51))
|
||||
|
||||
rangeTest('test iterator with lt=50555 (midway)', {
|
||||
lt: '50555'
|
||||
}, data.slice(0, 51))
|
||||
|
||||
rangeTest('test iterator with gte=50.5 (midway) and reverse=true', {
|
||||
gte: '50.5',
|
||||
reverse: true
|
||||
}, data.slice().reverse().slice(0, 49))
|
||||
|
||||
rangeTest('test iterator with gt=50.5 (midway) and reverse=true', {
|
||||
gt: '50.5',
|
||||
reverse: true
|
||||
}, data.slice().reverse().slice(0, 49))
|
||||
|
||||
rangeTest('test iterator with gt=50 and reverse=true', {
|
||||
gt: '50',
|
||||
reverse: true
|
||||
}, data.slice().reverse().slice(0, 49))
|
||||
|
||||
// first key is actually '00' so it should avoid it
|
||||
rangeTest('test iterator with lte=0', {
|
||||
lte: '0'
|
||||
}, [])
|
||||
|
||||
// first key is actually '00' so it should avoid it
|
||||
rangeTest('test iterator with lt=0', {
|
||||
lt: '0'
|
||||
}, [])
|
||||
|
||||
rangeTest('test iterator with gte=30 and lte=70', {
|
||||
gte: '30',
|
||||
lte: '70'
|
||||
}, data.slice(30, 71))
|
||||
|
||||
// The gte and lte options should take precedence over gt and lt respectively.
|
||||
rangeTest('test iterator with gte=30 and lte=70 and gt=40 and lt=60', {
|
||||
gte: '30',
|
||||
lte: '70',
|
||||
gt: '40',
|
||||
lt: '60'
|
||||
}, data.slice(30, 71))
|
||||
|
||||
// Also test the other way around: if gt and lt were to select a bigger range.
|
||||
rangeTest('test iterator with gte=30 and lte=70 and gt=20 and lt=80', {
|
||||
gte: '30',
|
||||
lte: '70',
|
||||
gt: '20',
|
||||
lt: '80'
|
||||
}, data.slice(30, 71))
|
||||
|
||||
rangeTest('test iterator with gt=29 and lt=71', {
|
||||
gt: '29',
|
||||
lt: '71'
|
||||
}, data.slice(30, 71))
|
||||
|
||||
rangeTest('test iterator with gte=30 and lte=70 and reverse=true', {
|
||||
lte: '70',
|
||||
gte: '30',
|
||||
reverse: true
|
||||
}, data.slice().reverse().slice(29, 70))
|
||||
|
||||
rangeTest('test iterator with gt=29 and lt=71 and reverse=true', {
|
||||
lt: '71',
|
||||
gt: '29',
|
||||
reverse: true
|
||||
}, data.slice().reverse().slice(29, 70))
|
||||
|
||||
rangeTest('test iterator with limit=20', {
|
||||
limit: 20
|
||||
}, data.slice(0, 20))
|
||||
|
||||
rangeTest('test iterator with limit=20 and gte=20', {
|
||||
limit: 20,
|
||||
gte: '20'
|
||||
}, data.slice(20, 40))
|
||||
|
||||
rangeTest('test iterator with limit=20 and reverse=true', {
|
||||
limit: 20,
|
||||
reverse: true
|
||||
}, data.slice().reverse().slice(0, 20))
|
||||
|
||||
rangeTest('test iterator with limit=20 and lte=79 and reverse=true', {
|
||||
limit: 20,
|
||||
lte: '79',
|
||||
reverse: true
|
||||
}, data.slice().reverse().slice(20, 40))
|
||||
|
||||
// the default limit value from levelup is -1
|
||||
rangeTest('test iterator with limit=-1 should iterate over whole database', {
|
||||
limit: -1
|
||||
}, data)
|
||||
|
||||
rangeTest('test iterator with limit=0 should not iterate over anything', {
|
||||
limit: 0
|
||||
}, [])
|
||||
|
||||
rangeTest('test iterator with lte after limit', {
|
||||
limit: 20,
|
||||
lte: '50'
|
||||
}, data.slice(0, 20))
|
||||
|
||||
rangeTest('test iterator with lte before limit', {
|
||||
limit: 50,
|
||||
lte: '19'
|
||||
}, data.slice(0, 20))
|
||||
|
||||
rangeTest('test iterator with gte after database end', {
|
||||
gte: '9a'
|
||||
}, [])
|
||||
|
||||
rangeTest('test iterator with gt after database end', {
|
||||
gt: '9a'
|
||||
}, [])
|
||||
|
||||
rangeTest('test iterator with lte after database end and reverse=true', {
|
||||
lte: '9a',
|
||||
reverse: true
|
||||
}, data.slice().reverse())
|
||||
|
||||
rangeTest('test iterator with lt after database end', {
|
||||
lt: 'a'
|
||||
}, data.slice())
|
||||
|
||||
rangeTest('test iterator with lt at database end', {
|
||||
lt: data[data.length - 1].key
|
||||
}, data.slice(0, -1))
|
||||
|
||||
rangeTest('test iterator with lte at database end', {
|
||||
lte: data[data.length - 1].key
|
||||
}, data.slice())
|
||||
|
||||
rangeTest('test iterator with lt before database end', {
|
||||
lt: data[data.length - 2].key
|
||||
}, data.slice(0, -2))
|
||||
|
||||
rangeTest('test iterator with lte before database end', {
|
||||
lte: data[data.length - 2].key
|
||||
}, data.slice(0, -1))
|
||||
|
||||
rangeTest('test iterator with lte and gte after database and reverse=true', {
|
||||
lte: '9b',
|
||||
gte: '9a',
|
||||
reverse: true
|
||||
}, [])
|
||||
|
||||
rangeTest('test iterator with lt and gt after database and reverse=true', {
|
||||
lt: '9b',
|
||||
gt: '9a',
|
||||
reverse: true
|
||||
}, [])
|
||||
|
||||
rangeTest('gt greater than lt', {
|
||||
gt: '20',
|
||||
lt: '10'
|
||||
}, [])
|
||||
|
||||
rangeTest('gte greater than lte', {
|
||||
gte: '20',
|
||||
lte: '10'
|
||||
}, [])
|
||||
}
|
||||
|
||||
exports.tearDown = function (test, testCommon) {
|
||||
test('tearDown', function (t) {
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.setUp(test, testCommon)
|
||||
exports.range(test, testCommon)
|
||||
exports.tearDown(test, testCommon)
|
||||
}
|
252
node_modules/abstract-level/test/iterator-seek-test.js
generated
vendored
Normal file
252
node_modules/abstract-level/test/iterator-seek-test.js
generated
vendored
Normal file
@ -0,0 +1,252 @@
|
||||
'use strict'
|
||||
|
||||
const { Buffer } = require('buffer')
|
||||
const identity = (v) => v
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.sequence(test, testCommon)
|
||||
exports.seek(test, testCommon)
|
||||
}
|
||||
|
||||
exports.sequence = function (test, testCommon) {
|
||||
for (const deferred of [false, true]) {
|
||||
for (const mode of ['iterator', 'keys', 'values']) {
|
||||
test(`${mode}().seek() throws if next() has not completed (deferred: ${deferred})`, async function (t) {
|
||||
const db = testCommon.factory()
|
||||
if (!deferred) await db.open()
|
||||
|
||||
const it = db[mode]()
|
||||
const promise = it.next()
|
||||
|
||||
t.throws(() => it.seek('two'), (err) => err.code === 'LEVEL_ITERATOR_BUSY')
|
||||
|
||||
await promise
|
||||
await db.close()
|
||||
})
|
||||
|
||||
test(`${mode}().seek() does not throw after close() (deferred: ${deferred})`, async function (t) {
|
||||
const db = testCommon.factory()
|
||||
if (!deferred) await db.open()
|
||||
|
||||
const it = db[mode]()
|
||||
await it.close()
|
||||
|
||||
t.doesNotThrow(() => it.seek('two'))
|
||||
|
||||
await db.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.seek = function (test, testCommon) {
|
||||
const testData = () => [
|
||||
{ type: 'put', key: 'one', value: '1' },
|
||||
{ type: 'put', key: 'two', value: '2' },
|
||||
{ type: 'put', key: 'three', value: '3' }
|
||||
]
|
||||
|
||||
for (const mode of ['iterator', 'keys', 'values']) {
|
||||
const mapEntry = mode === 'iterator' ? e => e : mode === 'keys' ? e => e[0] : e => e[1]
|
||||
|
||||
test(`${mode}().seek() to string target`, async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.batch(testData())
|
||||
const it = db[mode]()
|
||||
|
||||
it.seek('two')
|
||||
|
||||
t.same(await it.next(), mapEntry(['two', '2']), 'match')
|
||||
t.same(await it.next(), undefined, 'end of iterator')
|
||||
|
||||
return db.close()
|
||||
})
|
||||
|
||||
if (testCommon.supports.encodings.buffer) {
|
||||
// TODO: make this test meaningful, with bytes outside the utf8 range
|
||||
test(`${mode}().seek() to buffer target`, async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.batch(testData())
|
||||
const it = db[mode]({ keyEncoding: 'buffer' })
|
||||
|
||||
it.seek(Buffer.from('two'))
|
||||
|
||||
t.same(await it.next(), mapEntry([Buffer.from('two'), '2']), 'match')
|
||||
t.same(await it.next(), undefined, 'end of iterator')
|
||||
|
||||
return db.close()
|
||||
})
|
||||
}
|
||||
|
||||
test(`${mode}().seek() to target with custom encoding`, async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.batch(testData())
|
||||
const it = db[mode]()
|
||||
const keyEncoding = { encode: () => 'two', decode: identity, format: 'utf8' }
|
||||
|
||||
it.seek('xyz', { keyEncoding })
|
||||
|
||||
t.same(await it.next(), mapEntry(['two', '2']), 'match')
|
||||
t.same(await it.next(), undefined, 'end of iterator')
|
||||
|
||||
return db.close()
|
||||
})
|
||||
|
||||
test(`${mode}().seek() on reverse iterator`, async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.batch(testData())
|
||||
const it = db[mode]({ reverse: true, limit: 1 })
|
||||
|
||||
// Should land on key equal to or smaller than 'three!' which is 'three'
|
||||
it.seek('three!')
|
||||
|
||||
t.same(await it.next(), mapEntry(['three', '3']), 'match')
|
||||
t.same(await it.next(), undefined, 'end of iterator')
|
||||
|
||||
return db.close()
|
||||
})
|
||||
|
||||
test(`${mode}().seek() to out of range target`, async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.batch(testData())
|
||||
const it = db[mode]()
|
||||
|
||||
it.seek('zzz')
|
||||
t.same(await it.next(), undefined, 'end of iterator')
|
||||
|
||||
return db.close()
|
||||
})
|
||||
|
||||
test(`${mode}().seek() on reverse iterator to out of range target`, async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.batch(testData())
|
||||
const it = db[mode]({ reverse: true })
|
||||
|
||||
it.seek('zzz')
|
||||
|
||||
t.same(await it.next(), mapEntry(['two', '2']), 'match')
|
||||
t.same(await it.next(), mapEntry(['three', '3']), 'match')
|
||||
t.same(await it.next(), mapEntry(['one', '1']), 'match')
|
||||
t.same(await it.next(), undefined, 'end of iterator')
|
||||
|
||||
return db.close()
|
||||
})
|
||||
|
||||
if (testCommon.supports.snapshots) {
|
||||
for (const reverse of [false, true]) {
|
||||
for (const deferred of [false, true]) {
|
||||
test(`${mode}().seek() respects snapshot (reverse: ${reverse}, deferred: ${deferred})`, async function (t) {
|
||||
const db = testCommon.factory()
|
||||
if (!deferred) await db.open()
|
||||
|
||||
const it = db[mode]({ reverse })
|
||||
|
||||
// Add entry after having created the iterator (and its snapshot)
|
||||
await db.put('a', 'a')
|
||||
|
||||
// Seeking should not create a new snapshot, which'd include the new entry
|
||||
it.seek('a')
|
||||
t.same(await it.next(), undefined)
|
||||
|
||||
return db.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test(`${mode}().seek() respects range`, function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.error(err, 'no error from open()')
|
||||
|
||||
// Can't use Array.fill() because IE
|
||||
const ops = []
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
ops.push({ type: 'put', key: String(i), value: String(i) })
|
||||
}
|
||||
|
||||
db.batch(ops, function (err) {
|
||||
t.error(err, 'no error from batch()')
|
||||
|
||||
let pending = 0
|
||||
|
||||
expect({ gt: '5' }, '4', undefined)
|
||||
expect({ gt: '5' }, '5', undefined)
|
||||
expect({ gt: '5' }, '6', '6')
|
||||
|
||||
expect({ gte: '5' }, '4', undefined)
|
||||
expect({ gte: '5' }, '5', '5')
|
||||
expect({ gte: '5' }, '6', '6')
|
||||
|
||||
// The gte option should take precedence over gt.
|
||||
expect({ gte: '5', gt: '7' }, '4', undefined)
|
||||
expect({ gte: '5', gt: '7' }, '5', '5')
|
||||
expect({ gte: '5', gt: '7' }, '6', '6')
|
||||
expect({ gte: '5', gt: '3' }, '4', undefined)
|
||||
expect({ gte: '5', gt: '3' }, '5', '5')
|
||||
expect({ gte: '5', gt: '3' }, '6', '6')
|
||||
|
||||
expect({ lt: '5' }, '4', '4')
|
||||
expect({ lt: '5' }, '5', undefined)
|
||||
expect({ lt: '5' }, '6', undefined)
|
||||
|
||||
expect({ lte: '5' }, '4', '4')
|
||||
expect({ lte: '5' }, '5', '5')
|
||||
expect({ lte: '5' }, '6', undefined)
|
||||
|
||||
// The lte option should take precedence over lt.
|
||||
expect({ lte: '5', lt: '3' }, '4', '4')
|
||||
expect({ lte: '5', lt: '3' }, '5', '5')
|
||||
expect({ lte: '5', lt: '3' }, '6', undefined)
|
||||
expect({ lte: '5', lt: '7' }, '4', '4')
|
||||
expect({ lte: '5', lt: '7' }, '5', '5')
|
||||
expect({ lte: '5', lt: '7' }, '6', undefined)
|
||||
|
||||
expect({ lt: '5', reverse: true }, '4', '4')
|
||||
expect({ lt: '5', reverse: true }, '5', undefined)
|
||||
expect({ lt: '5', reverse: true }, '6', undefined)
|
||||
|
||||
expect({ lte: '5', reverse: true }, '4', '4')
|
||||
expect({ lte: '5', reverse: true }, '5', '5')
|
||||
expect({ lte: '5', reverse: true }, '6', undefined)
|
||||
|
||||
expect({ gt: '5', reverse: true }, '4', undefined)
|
||||
expect({ gt: '5', reverse: true }, '5', undefined)
|
||||
expect({ gt: '5', reverse: true }, '6', '6')
|
||||
|
||||
expect({ gte: '5', reverse: true }, '4', undefined)
|
||||
expect({ gte: '5', reverse: true }, '5', '5')
|
||||
expect({ gte: '5', reverse: true }, '6', '6')
|
||||
|
||||
expect({ gt: '7', lt: '8' }, '7', undefined)
|
||||
expect({ gte: '7', lt: '8' }, '7', '7')
|
||||
expect({ gte: '7', lt: '8' }, '8', undefined)
|
||||
expect({ gt: '7', lte: '8' }, '8', '8')
|
||||
|
||||
function expect (range, target, expected) {
|
||||
pending++
|
||||
const ite = db[mode](range)
|
||||
|
||||
ite.seek(target)
|
||||
ite.next(function (err, item) {
|
||||
t.error(err, 'no error from next()')
|
||||
|
||||
const json = JSON.stringify(range)
|
||||
const msg = 'seek(' + target + ') on ' + json + ' yields ' + expected
|
||||
|
||||
// Either a key or value depending on mode
|
||||
t.is(item, expected, msg)
|
||||
|
||||
ite.close(function (err) {
|
||||
t.error(err, 'no error from close()')
|
||||
if (!--pending) db.close(t.end.bind(t))
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
99
node_modules/abstract-level/test/iterator-snapshot-test.js
generated
vendored
Normal file
99
node_modules/abstract-level/test/iterator-snapshot-test.js
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
'use strict'
|
||||
|
||||
exports.snapshot = function (test, testCommon) {
|
||||
function make (run) {
|
||||
return function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open error')
|
||||
|
||||
db.put('z', 'from snapshot', function (err) {
|
||||
t.ifError(err, 'no put error')
|
||||
|
||||
// For this test it is important that we don't read eagerly.
|
||||
// NOTE: highWaterMarkBytes is not an abstract option, but
|
||||
// it is supported by classic-level and others. Also set the
|
||||
// old & equivalent leveldown highWaterMark option for compat.
|
||||
const it = db.iterator({ highWaterMarkBytes: 0, highWaterMark: 0 })
|
||||
|
||||
run(t, db, it, function end (err) {
|
||||
t.ifError(err, 'no run error')
|
||||
|
||||
it.close(function (err) {
|
||||
t.ifError(err, 'no iterator close error')
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
test('delete key after snapshotting', make(function (t, db, it, end) {
|
||||
db.del('z', function (err) {
|
||||
t.ifError(err, 'no del error')
|
||||
|
||||
it.next(function (err, key, value) {
|
||||
t.ifError(err, 'no next error')
|
||||
t.ok(key, 'got a key')
|
||||
t.is(key.toString(), 'z', 'correct key')
|
||||
t.is(value.toString(), 'from snapshot', 'correct value')
|
||||
|
||||
end()
|
||||
})
|
||||
})
|
||||
}))
|
||||
|
||||
test('overwrite key after snapshotting', make(function (t, db, it, end) {
|
||||
db.put('z', 'not from snapshot', function (err) {
|
||||
t.ifError(err, 'no put error')
|
||||
|
||||
it.next(function (err, key, value) {
|
||||
t.ifError(err, 'no next error')
|
||||
t.ok(key, 'got a key')
|
||||
t.is(key.toString(), 'z', 'correct key')
|
||||
t.is(value.toString(), 'from snapshot', 'correct value')
|
||||
|
||||
end()
|
||||
})
|
||||
})
|
||||
}))
|
||||
|
||||
test('add key after snapshotting that sorts first', make(function (t, db, it, end) {
|
||||
db.put('a', 'not from snapshot', function (err) {
|
||||
t.ifError(err, 'no put error')
|
||||
|
||||
it.next(function (err, key, value) {
|
||||
t.ifError(err, 'no next error')
|
||||
|
||||
t.ok(key, 'got a key')
|
||||
t.is(key.toString(), 'z', 'correct key')
|
||||
t.is(value.toString(), 'from snapshot', 'correct value')
|
||||
|
||||
end()
|
||||
})
|
||||
})
|
||||
}))
|
||||
|
||||
// NOTE: adapted from memdown
|
||||
test('delete key after snapshotting, with more entries available', async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
await Promise.all([db.put('a', 'A'), db.put('b', 'B'), db.put('c', 'C')])
|
||||
|
||||
const iterator = db.iterator({ gte: 'a' })
|
||||
t.same(await iterator.next(), ['a', 'A'])
|
||||
|
||||
await db.del('b')
|
||||
t.same(await iterator.next(), ['b', 'B'])
|
||||
t.same(await iterator.next(), ['c', 'C'])
|
||||
|
||||
await iterator.close()
|
||||
return db.close()
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.snapshot(test, testCommon)
|
||||
}
|
548
node_modules/abstract-level/test/iterator-test.js
generated
vendored
Normal file
548
node_modules/abstract-level/test/iterator-test.js
generated
vendored
Normal file
@ -0,0 +1,548 @@
|
||||
'use strict'
|
||||
|
||||
const { Buffer } = require('buffer')
|
||||
const identity = (v) => v
|
||||
|
||||
let db
|
||||
|
||||
exports.setUp = function (test, testCommon) {
|
||||
test('setUp db', function (t) {
|
||||
db = testCommon.factory()
|
||||
db.open(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.args = function (test, testCommon) {
|
||||
for (const mode of ['iterator', 'keys', 'values']) {
|
||||
test(`${mode}() has db reference`, async function (t) {
|
||||
const it = db[mode]()
|
||||
|
||||
// May return iterator of an underlying db, that's okay.
|
||||
t.ok(it.db === db || it.db === (db.db || db._db || db))
|
||||
|
||||
await it.close()
|
||||
})
|
||||
|
||||
test(`${mode}() has limit and count properties`, async function (t) {
|
||||
const iterators = [db[mode]()]
|
||||
t.is(iterators[0].limit, Infinity, 'defaults to infinite')
|
||||
|
||||
for (const limit of [-1, 0, 1, Infinity]) {
|
||||
const it = db[mode]({ limit })
|
||||
iterators.push(it)
|
||||
t.is(it.limit, limit === -1 ? Infinity : limit, 'has limit property')
|
||||
}
|
||||
|
||||
t.ok(iterators.every(it => it.count === 0), 'has count property')
|
||||
await Promise.all(iterators.map(it => it.close()))
|
||||
})
|
||||
|
||||
test(`${mode}().nextv() yields error if size is invalid`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const it = db[mode]()
|
||||
|
||||
for (const args of [[], [NaN], ['1'], [2.5]]) {
|
||||
try {
|
||||
await it.nextv(...args)
|
||||
} catch (err) {
|
||||
t.is(err.message, "The first argument 'size' must be an integer")
|
||||
}
|
||||
}
|
||||
|
||||
await it.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
exports.sequence = function (test, testCommon) {
|
||||
for (const mode of ['iterator', 'keys', 'values']) {
|
||||
test(`${mode}().close() is idempotent`, function (t) {
|
||||
const iterator = db[mode]()
|
||||
|
||||
iterator.close(function () {
|
||||
let async = false
|
||||
|
||||
iterator.close(function () {
|
||||
t.ok(async, 'callback is asynchronous')
|
||||
t.end()
|
||||
})
|
||||
|
||||
async = true
|
||||
})
|
||||
})
|
||||
|
||||
for (const method of ['next', 'nextv', 'all']) {
|
||||
const requiredArgs = method === 'nextv' ? [1] : []
|
||||
|
||||
test(`${mode}().${method}() after close() yields error`, function (t) {
|
||||
const iterator = db[mode]()
|
||||
iterator.close(function (err) {
|
||||
t.error(err)
|
||||
|
||||
let async = false
|
||||
|
||||
iterator[method](...requiredArgs, function (err2) {
|
||||
t.ok(err2, 'returned error')
|
||||
t.is(err2.code, 'LEVEL_ITERATOR_NOT_OPEN', 'correct message')
|
||||
t.ok(async, 'callback is asynchronous')
|
||||
t.end()
|
||||
})
|
||||
|
||||
async = true
|
||||
})
|
||||
})
|
||||
|
||||
for (const otherMethod of ['next', 'nextv', 'all']) {
|
||||
const otherRequiredArgs = otherMethod === 'nextv' ? [1] : []
|
||||
|
||||
test(`${mode}().${method}() while busy with ${otherMethod}() yields error`, function (t) {
|
||||
const iterator = db[mode]()
|
||||
iterator[otherMethod](...otherRequiredArgs, function (err) {
|
||||
t.error(err)
|
||||
iterator.close(function (err) {
|
||||
t.error(err)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
let async = false
|
||||
|
||||
iterator[method](...requiredArgs, function (err) {
|
||||
t.ok(err, 'returned error')
|
||||
t.is(err.code, 'LEVEL_ITERATOR_BUSY')
|
||||
t.ok(async, 'callback is asynchronous')
|
||||
})
|
||||
|
||||
async = true
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const deferred of [false, true]) {
|
||||
for (const mode of ['iterator', 'keys', 'values']) {
|
||||
for (const method of ['next', 'nextv', 'all']) {
|
||||
const requiredArgs = method === 'nextv' ? [10] : []
|
||||
|
||||
// NOTE: adapted from leveldown
|
||||
test(`${mode}().${method}() after db.close() yields error (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
const db = testCommon.factory()
|
||||
if (!deferred) await db.open()
|
||||
|
||||
await db.put('a', 'a')
|
||||
await db.put('b', 'b')
|
||||
|
||||
const it = db[mode]()
|
||||
|
||||
// The first call *should* succeed, because it was scheduled before close(). However, success
|
||||
// is not a must. Because nextv() and all() fallback to next*(), they're allowed to fail. An
|
||||
// implementation can also choose to abort any pending call on close.
|
||||
let promise = it[method](...requiredArgs).then(() => {
|
||||
t.pass('Optionally succeeded')
|
||||
}).catch((err) => {
|
||||
t.is(err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
})
|
||||
|
||||
// The second call *must* fail, because it was scheduled after close()
|
||||
promise = promise.then(() => {
|
||||
return it[method](...requiredArgs).then(() => {
|
||||
t.fail('Expected an error')
|
||||
}).catch((err) => {
|
||||
t.is(err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
})
|
||||
})
|
||||
|
||||
return Promise.all([db.close(), promise])
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.iterator = function (test, testCommon) {
|
||||
test('test simple iterator()', function (t) {
|
||||
const data = [
|
||||
{ type: 'put', key: 'foobatch1', value: 'bar1' },
|
||||
{ type: 'put', key: 'foobatch2', value: 'bar2' },
|
||||
{ type: 'put', key: 'foobatch3', value: 'bar3' }
|
||||
]
|
||||
let idx = 0
|
||||
|
||||
db.batch(data, function (err) {
|
||||
t.error(err)
|
||||
const iterator = db.iterator()
|
||||
const fn = function (err, key, value) {
|
||||
t.error(err)
|
||||
if (key && value) {
|
||||
t.is(key, data[idx].key, 'correct key')
|
||||
t.is(value, data[idx].value, 'correct value')
|
||||
db.nextTick(next)
|
||||
idx++
|
||||
} else { // end
|
||||
t.ok(err == null, 'err argument is nullish')
|
||||
t.ok(typeof key === 'undefined', 'key argument is undefined')
|
||||
t.ok(typeof value === 'undefined', 'value argument is undefined')
|
||||
t.is(idx, data.length, 'correct number of entries')
|
||||
iterator.close(function () {
|
||||
t.end()
|
||||
})
|
||||
}
|
||||
}
|
||||
const next = function () {
|
||||
iterator.next(fn)
|
||||
}
|
||||
|
||||
next()
|
||||
})
|
||||
})
|
||||
|
||||
// NOTE: adapted from leveldown
|
||||
test('key-only iterator', function (t) {
|
||||
const it = db.iterator({ values: false })
|
||||
|
||||
it.next(function (err, key, value) {
|
||||
t.ifError(err, 'no next() error')
|
||||
t.is(key, 'foobatch1')
|
||||
t.is(value, undefined)
|
||||
it.close(t.end.bind(t))
|
||||
})
|
||||
})
|
||||
|
||||
// NOTE: adapted from leveldown
|
||||
test('value-only iterator', function (t) {
|
||||
const it = db.iterator({ keys: false })
|
||||
|
||||
it.next(function (err, key, value) {
|
||||
t.ifError(err, 'no next() error')
|
||||
t.is(key, undefined)
|
||||
t.is(value, 'bar1')
|
||||
it.close(t.end.bind(t))
|
||||
})
|
||||
})
|
||||
|
||||
test('db.keys().next()', function (t) {
|
||||
const it = db.keys()
|
||||
|
||||
it.next(function (err, key) {
|
||||
t.ifError(err, 'no next() error')
|
||||
t.is(key, 'foobatch1')
|
||||
it.close(t.end.bind(t))
|
||||
})
|
||||
})
|
||||
|
||||
test('db.values().next()', function (t) {
|
||||
const it = db.values()
|
||||
|
||||
it.next(function (err, value) {
|
||||
t.ifError(err, 'no next() error')
|
||||
t.is(value, 'bar1')
|
||||
it.close(t.end.bind(t))
|
||||
})
|
||||
})
|
||||
|
||||
for (const mode of ['iterator', 'keys', 'values']) {
|
||||
const mapEntry = e => mode === 'iterator' ? e : mode === 'keys' ? e[0] : e[1]
|
||||
|
||||
test(`${mode}().nextv()`, async function (t) {
|
||||
const it = db[mode]()
|
||||
|
||||
t.same(await it.nextv(1), [['foobatch1', 'bar1']].map(mapEntry))
|
||||
t.same(await it.nextv(2, {}), [['foobatch2', 'bar2'], ['foobatch3', 'bar3']].map(mapEntry))
|
||||
t.same(await it.nextv(2), [])
|
||||
|
||||
await it.close()
|
||||
})
|
||||
|
||||
test(`${mode}().nextv() in reverse`, async function (t) {
|
||||
const it = db[mode]({ reverse: true })
|
||||
|
||||
t.same(await it.nextv(1), [['foobatch3', 'bar3']].map(mapEntry))
|
||||
t.same(await it.nextv(2, {}), [['foobatch2', 'bar2'], ['foobatch1', 'bar1']].map(mapEntry))
|
||||
t.same(await it.nextv(2), [])
|
||||
|
||||
await it.close()
|
||||
})
|
||||
|
||||
test(`${mode}().nextv() has soft minimum of 1`, async function (t) {
|
||||
const it = db[mode]()
|
||||
|
||||
t.same(await it.nextv(0), [['foobatch1', 'bar1']].map(mapEntry))
|
||||
t.same(await it.nextv(0), [['foobatch2', 'bar2']].map(mapEntry))
|
||||
t.same(await it.nextv(0, {}), [['foobatch3', 'bar3']].map(mapEntry))
|
||||
t.same(await it.nextv(0), [])
|
||||
|
||||
await it.close()
|
||||
})
|
||||
|
||||
test(`${mode}().nextv() requesting more than available`, async function (t) {
|
||||
const it = db[mode]()
|
||||
|
||||
t.same(await it.nextv(10), [
|
||||
['foobatch1', 'bar1'],
|
||||
['foobatch2', 'bar2'],
|
||||
['foobatch3', 'bar3']
|
||||
].map(mapEntry))
|
||||
t.same(await it.nextv(10), [])
|
||||
|
||||
await it.close()
|
||||
})
|
||||
|
||||
test(`${mode}().nextv() honors limit`, async function (t) {
|
||||
const it = db[mode]({ limit: 2 })
|
||||
|
||||
t.same(await it.nextv(10), [['foobatch1', 'bar1'], ['foobatch2', 'bar2']].map(mapEntry))
|
||||
t.same(await it.nextv(10), [])
|
||||
|
||||
await it.close()
|
||||
})
|
||||
|
||||
test(`${mode}().nextv() honors limit in reverse`, async function (t) {
|
||||
const it = db[mode]({ limit: 2, reverse: true })
|
||||
|
||||
t.same(await it.nextv(10), [['foobatch3', 'bar3'], ['foobatch2', 'bar2']].map(mapEntry))
|
||||
t.same(await it.nextv(10), [])
|
||||
|
||||
await it.close()
|
||||
})
|
||||
|
||||
test(`${mode}().all()`, async function (t) {
|
||||
t.same(await db[mode]().all(), [
|
||||
['foobatch1', 'bar1'],
|
||||
['foobatch2', 'bar2'],
|
||||
['foobatch3', 'bar3']
|
||||
].map(mapEntry))
|
||||
|
||||
t.same(await db[mode]().all({}), [
|
||||
['foobatch1', 'bar1'],
|
||||
['foobatch2', 'bar2'],
|
||||
['foobatch3', 'bar3']
|
||||
].map(mapEntry))
|
||||
})
|
||||
|
||||
test(`${mode}().all() in reverse`, async function (t) {
|
||||
t.same(await db[mode]({ reverse: true }).all(), [
|
||||
['foobatch3', 'bar3'],
|
||||
['foobatch2', 'bar2'],
|
||||
['foobatch1', 'bar1']
|
||||
].map(mapEntry))
|
||||
})
|
||||
|
||||
test(`${mode}().all() honors limit`, async function (t) {
|
||||
t.same(await db[mode]({ limit: 2 }).all(), [
|
||||
['foobatch1', 'bar1'],
|
||||
['foobatch2', 'bar2']
|
||||
].map(mapEntry))
|
||||
|
||||
const it = db[mode]({ limit: 2 })
|
||||
|
||||
t.same(await it.next(), mapEntry(['foobatch1', 'bar1']))
|
||||
t.same(await it.all(), [['foobatch2', 'bar2']].map(mapEntry))
|
||||
})
|
||||
|
||||
test(`${mode}().all() honors limit in reverse`, async function (t) {
|
||||
t.same(await db[mode]({ limit: 2, reverse: true }).all(), [
|
||||
['foobatch3', 'bar3'],
|
||||
['foobatch2', 'bar2']
|
||||
].map(mapEntry))
|
||||
|
||||
const it = db[mode]({ limit: 2, reverse: true })
|
||||
|
||||
t.same(await it.next(), mapEntry(['foobatch3', 'bar3']))
|
||||
t.same(await it.all(), [['foobatch2', 'bar2']].map(mapEntry))
|
||||
})
|
||||
}
|
||||
|
||||
// NOTE: adapted from memdown
|
||||
test('iterator() sorts lexicographically', async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
|
||||
// Write in unsorted order with multiple operations
|
||||
await db.put('f', 'F')
|
||||
await db.put('a', 'A')
|
||||
await db.put('~', '~')
|
||||
await db.put('e', 'E')
|
||||
await db.put('🐄', '🐄')
|
||||
await db.batch([
|
||||
{ type: 'put', key: 'd', value: 'D' },
|
||||
{ type: 'put', key: 'b', value: 'B' },
|
||||
{ type: 'put', key: 'ff', value: 'FF' },
|
||||
{ type: 'put', key: 'a🐄', value: 'A🐄' }
|
||||
])
|
||||
await db.batch([
|
||||
{ type: 'put', key: '', value: 'empty' },
|
||||
{ type: 'put', key: '2', value: '2' },
|
||||
{ type: 'put', key: '12', value: '12' },
|
||||
{ type: 'put', key: '\t', value: '\t' }
|
||||
])
|
||||
|
||||
t.same(await db.iterator().all(), [
|
||||
['', 'empty'],
|
||||
['\t', '\t'],
|
||||
['12', '12'],
|
||||
['2', '2'],
|
||||
['a', 'A'],
|
||||
['a🐄', 'A🐄'],
|
||||
['b', 'B'],
|
||||
['d', 'D'],
|
||||
['e', 'E'],
|
||||
['f', 'F'],
|
||||
['ff', 'FF'],
|
||||
['~', '~'],
|
||||
['🐄', '🐄']
|
||||
])
|
||||
|
||||
t.same(await db.iterator({ lte: '' }).all(), [
|
||||
['', 'empty']
|
||||
])
|
||||
|
||||
return db.close()
|
||||
})
|
||||
|
||||
for (const keyEncoding of ['buffer', 'view']) {
|
||||
if (!testCommon.supports.encodings[keyEncoding]) continue
|
||||
|
||||
test(`test iterator() has byte order (${keyEncoding} encoding)`, function (t) {
|
||||
const db = testCommon.factory({ keyEncoding })
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open() error')
|
||||
|
||||
const ctor = keyEncoding === 'buffer' ? Buffer : Uint8Array
|
||||
const keys = [2, 11, 1].map(b => ctor.from([b]))
|
||||
|
||||
db.batch(keys.map((key) => ({ type: 'put', key, value: 'x' })), function (err) {
|
||||
t.ifError(err, 'no batch() error')
|
||||
|
||||
db.keys().all(function (err, keys) {
|
||||
t.ifError(err, 'no all() error')
|
||||
t.same(keys.map(k => k[0]), [1, 2, 11], 'order is ok')
|
||||
|
||||
db.iterator().all(function (err, entries) {
|
||||
t.ifError(err, 'no all() error')
|
||||
t.same(entries.map(e => e[0][0]), [1, 2, 11], 'order is ok')
|
||||
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// NOTE: adapted from memdown and level-js
|
||||
test(`test iterator() with byte range (${keyEncoding} encoding)`, async function (t) {
|
||||
const db = testCommon.factory({ keyEncoding })
|
||||
await db.open()
|
||||
|
||||
await db.put(Uint8Array.from([0x0]), '0')
|
||||
await db.put(Uint8Array.from([128]), '128')
|
||||
await db.put(Uint8Array.from([160]), '160')
|
||||
await db.put(Uint8Array.from([192]), '192')
|
||||
|
||||
const collect = async (range) => {
|
||||
const entries = await db.iterator(range).all()
|
||||
t.ok(entries.every(e => e[0] instanceof Uint8Array)) // True for both encodings
|
||||
t.ok(entries.every(e => e[1] === String(e[0][0])))
|
||||
return entries.map(e => e[0][0])
|
||||
}
|
||||
|
||||
t.same(await collect({ gt: Uint8Array.from([255]) }), [])
|
||||
t.same(await collect({ gt: Uint8Array.from([192]) }), [])
|
||||
t.same(await collect({ gt: Uint8Array.from([160]) }), [192])
|
||||
t.same(await collect({ gt: Uint8Array.from([128]) }), [160, 192])
|
||||
t.same(await collect({ gt: Uint8Array.from([0x0]) }), [128, 160, 192])
|
||||
t.same(await collect({ gt: Uint8Array.from([]) }), [0x0, 128, 160, 192])
|
||||
|
||||
t.same(await collect({ lt: Uint8Array.from([255]) }), [0x0, 128, 160, 192])
|
||||
t.same(await collect({ lt: Uint8Array.from([192]) }), [0x0, 128, 160])
|
||||
t.same(await collect({ lt: Uint8Array.from([160]) }), [0x0, 128])
|
||||
t.same(await collect({ lt: Uint8Array.from([128]) }), [0x0])
|
||||
t.same(await collect({ lt: Uint8Array.from([0x0]) }), [])
|
||||
t.same(await collect({ lt: Uint8Array.from([]) }), [])
|
||||
|
||||
t.same(await collect({ gte: Uint8Array.from([255]) }), [])
|
||||
t.same(await collect({ gte: Uint8Array.from([192]) }), [192])
|
||||
t.same(await collect({ gte: Uint8Array.from([160]) }), [160, 192])
|
||||
t.same(await collect({ gte: Uint8Array.from([128]) }), [128, 160, 192])
|
||||
t.same(await collect({ gte: Uint8Array.from([0x0]) }), [0x0, 128, 160, 192])
|
||||
t.same(await collect({ gte: Uint8Array.from([]) }), [0x0, 128, 160, 192])
|
||||
|
||||
t.same(await collect({ lte: Uint8Array.from([255]) }), [0x0, 128, 160, 192])
|
||||
t.same(await collect({ lte: Uint8Array.from([192]) }), [0x0, 128, 160, 192])
|
||||
t.same(await collect({ lte: Uint8Array.from([160]) }), [0x0, 128, 160])
|
||||
t.same(await collect({ lte: Uint8Array.from([128]) }), [0x0, 128])
|
||||
t.same(await collect({ lte: Uint8Array.from([0x0]) }), [0x0])
|
||||
t.same(await collect({ lte: Uint8Array.from([]) }), [])
|
||||
|
||||
return db.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
exports.decode = function (test, testCommon) {
|
||||
for (const deferred of [false, true]) {
|
||||
for (const mode of ['iterator', 'keys', 'values']) {
|
||||
for (const method of ['next', 'nextv', 'all']) {
|
||||
const requiredArgs = method === 'nextv' ? [1] : []
|
||||
|
||||
for (const encodingOption of ['keyEncoding', 'valueEncoding']) {
|
||||
if (mode === 'keys' && encodingOption === 'valueEncoding') continue
|
||||
if (mode === 'values' && encodingOption === 'keyEncoding') continue
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`${mode}().${method}() catches decoding error from ${encodingOption} (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const encoding = {
|
||||
format: 'utf8',
|
||||
decode: function (x) {
|
||||
t.is(x, encodingOption === 'keyEncoding' ? 'testKey' : 'testValue')
|
||||
throw new Error('from encoding')
|
||||
},
|
||||
encode: identity
|
||||
}
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.put('testKey', 'testValue')
|
||||
|
||||
if (deferred) {
|
||||
await db.close()
|
||||
db.open(t.ifError.bind(t))
|
||||
} else {
|
||||
t.pass('non-deferred')
|
||||
}
|
||||
|
||||
const it = db[mode]({ [encodingOption]: encoding })
|
||||
|
||||
try {
|
||||
await it[method](...requiredArgs)
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_DECODE_ERROR')
|
||||
t.is(err.cause && err.cause.message, 'from encoding')
|
||||
}
|
||||
|
||||
return db.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.tearDown = function (test, testCommon) {
|
||||
test('tearDown', function (t) {
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.setUp(test, testCommon)
|
||||
exports.args(test, testCommon)
|
||||
exports.sequence(test, testCommon)
|
||||
exports.iterator(test, testCommon)
|
||||
exports.decode(test, testCommon)
|
||||
exports.tearDown(test, testCommon)
|
||||
}
|
24
node_modules/abstract-level/test/manifest-test.js
generated
vendored
Normal file
24
node_modules/abstract-level/test/manifest-test.js
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
'use strict'
|
||||
|
||||
const suite = require('level-supports/test')
|
||||
|
||||
module.exports = function (test, testCommon) {
|
||||
suite(test, testCommon)
|
||||
|
||||
test('manifest has expected properties', function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
t.is(db.supports.status, true)
|
||||
t.is(db.supports.promises, true)
|
||||
t.is(db.supports.clear, true)
|
||||
t.is(db.supports.getMany, true)
|
||||
|
||||
testCommon.supports = db.supports
|
||||
t.ok(testCommon.supports, 'can be accessed via testCommon')
|
||||
|
||||
t.ok(db.supports.encodings.utf8, 'supports utf8')
|
||||
t.ok(db.supports.encodings.json, 'supports json')
|
||||
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
}
|
35
node_modules/abstract-level/test/open-create-if-missing-test.js
generated
vendored
Normal file
35
node_modules/abstract-level/test/open-create-if-missing-test.js
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
'use strict'
|
||||
|
||||
exports.createIfMissing = function (test, testCommon) {
|
||||
test('test database open createIfMissing:false', function (t) {
|
||||
const db = testCommon.factory()
|
||||
let async = false
|
||||
|
||||
db.open({ createIfMissing: false }, function (err) {
|
||||
t.is(err && err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
t.ok(err && /does not exist/.test(err.cause && err.cause.message), 'error is about dir not existing')
|
||||
t.ok(async, 'callback is asynchronous')
|
||||
t.end()
|
||||
})
|
||||
|
||||
async = true
|
||||
})
|
||||
|
||||
test('test database open createIfMissing:false via constructor', function (t) {
|
||||
const db = testCommon.factory({ createIfMissing: false })
|
||||
let async = false
|
||||
|
||||
db.open(function (err) {
|
||||
t.is(err && err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
t.ok(err && /does not exist/.test(err.cause && err.cause.message), 'error is about dir not existing')
|
||||
t.ok(async, 'callback is asynchronous')
|
||||
t.end()
|
||||
})
|
||||
|
||||
async = true
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.createIfMissing(test, testCommon)
|
||||
}
|
29
node_modules/abstract-level/test/open-error-if-exists-test.js
generated
vendored
Normal file
29
node_modules/abstract-level/test/open-error-if-exists-test.js
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
'use strict'
|
||||
|
||||
exports.errorIfExists = function (test, testCommon) {
|
||||
test('test database open errorIfExists:true', function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.error(err)
|
||||
db.close(function (err) {
|
||||
t.error(err)
|
||||
|
||||
let async = false
|
||||
|
||||
db.open({ createIfMissing: false, errorIfExists: true }, function (err) {
|
||||
t.is(err && err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
t.ok(err && /exists/.test(err.cause && err.cause.message), 'error is about already existing')
|
||||
t.ok(async, 'callback is asynchronous')
|
||||
t.end()
|
||||
})
|
||||
|
||||
async = true
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.errorIfExists(test, testCommon)
|
||||
}
|
297
node_modules/abstract-level/test/open-test.js
generated
vendored
Normal file
297
node_modules/abstract-level/test/open-test.js
generated
vendored
Normal file
@ -0,0 +1,297 @@
|
||||
'use strict'
|
||||
|
||||
const { assertAsync } = require('./util')
|
||||
|
||||
exports.open = function (test, testCommon) {
|
||||
test('test database open, no options', function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
t.is(db.status, 'opening')
|
||||
|
||||
// default createIfMissing=true, errorIfExists=false
|
||||
db.open(function (err) {
|
||||
t.error(err)
|
||||
t.is(db.status, 'open')
|
||||
|
||||
db.close(function () {
|
||||
t.is(db.status, 'closed')
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.is(db.status, 'opening')
|
||||
})
|
||||
|
||||
test('test database open, no options, with promise', function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
t.is(db.status, 'opening')
|
||||
|
||||
// default createIfMissing=true, errorIfExists=false
|
||||
db.open().then(function () {
|
||||
t.is(db.status, 'open')
|
||||
db.close(t.end.bind(t))
|
||||
}).catch(t.fail.bind(t))
|
||||
|
||||
t.is(db.status, 'opening')
|
||||
})
|
||||
|
||||
test('test database open, options and callback', function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
// default createIfMissing=true, errorIfExists=false
|
||||
db.open({}, function (err) {
|
||||
t.error(err)
|
||||
db.close(function () {
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('test database open, options with promise', function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
// default createIfMissing=true, errorIfExists=false
|
||||
db.open({}).then(function () {
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
})
|
||||
|
||||
test('test database open, close and open', function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.error(err)
|
||||
|
||||
db.close(function (err) {
|
||||
t.error(err)
|
||||
t.is(db.status, 'closed')
|
||||
|
||||
db.open(function (err) {
|
||||
t.error(err)
|
||||
t.is(db.status, 'open')
|
||||
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('test database open, close and open with promise', function (t) {
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open().then(function () {
|
||||
db.close(function (err) {
|
||||
t.error(err)
|
||||
db.open().then(function () {
|
||||
db.close(function () {
|
||||
t.end()
|
||||
})
|
||||
}).catch(t.fail.bind(t))
|
||||
})
|
||||
}).catch(t.fail.bind(t))
|
||||
})
|
||||
|
||||
test('test database open and close in same tick', assertAsync.ctx(function (t) {
|
||||
t.plan(10)
|
||||
|
||||
const db = testCommon.factory()
|
||||
const order = []
|
||||
|
||||
db.open(assertAsync(function (err) {
|
||||
order.push('A')
|
||||
t.is(err && err.code, 'LEVEL_DATABASE_NOT_OPEN', 'got open() error')
|
||||
t.is(db.status, 'closed', 'is closed')
|
||||
}))
|
||||
|
||||
t.is(db.status, 'opening', 'is opening')
|
||||
|
||||
// This wins from the open() call
|
||||
db.close(assertAsync(function (err) {
|
||||
order.push('B')
|
||||
t.same(order, ['A', 'closed event', 'B'], 'order is correct')
|
||||
t.ifError(err, 'no close() error')
|
||||
t.is(db.status, 'closed', 'is closed')
|
||||
}))
|
||||
|
||||
// But open() is still in control
|
||||
t.is(db.status, 'opening', 'is still opening')
|
||||
|
||||
// Should not emit 'open', because close() wins
|
||||
db.on('open', t.fail.bind(t))
|
||||
db.on('closed', assertAsync(() => { order.push('closed event') }))
|
||||
}))
|
||||
|
||||
test('test database open, close and open in same tick', assertAsync.ctx(function (t) {
|
||||
t.plan(14)
|
||||
|
||||
const db = testCommon.factory()
|
||||
const order = []
|
||||
|
||||
db.open(assertAsync(function (err) {
|
||||
order.push('A')
|
||||
t.ifError(err, 'no open() error (1)')
|
||||
t.is(db.status, 'open', 'is open')
|
||||
}))
|
||||
|
||||
t.is(db.status, 'opening', 'is opening')
|
||||
|
||||
// This wins from the open() call
|
||||
db.close(assertAsync(function (err) {
|
||||
order.push('B')
|
||||
t.is(err && err.code, 'LEVEL_DATABASE_NOT_CLOSED')
|
||||
t.is(db.status, 'open', 'is open')
|
||||
}))
|
||||
|
||||
t.is(db.status, 'opening', 'is still opening')
|
||||
|
||||
// This wins from the close() call
|
||||
db.open(assertAsync(function (err) {
|
||||
order.push('C')
|
||||
t.same(order, ['A', 'B', 'open event', 'C'], 'callback order is the same as call order')
|
||||
t.ifError(err, 'no open() error (2)')
|
||||
t.is(db.status, 'open', 'is open')
|
||||
}))
|
||||
|
||||
// Should not emit 'closed', because open() wins
|
||||
db.on('closed', t.fail.bind(t))
|
||||
db.on('open', assertAsync(() => { order.push('open event') }))
|
||||
|
||||
t.is(db.status, 'opening', 'is still opening')
|
||||
}))
|
||||
|
||||
test('test database open if already open (sequential)', function (t) {
|
||||
t.plan(7)
|
||||
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(assertAsync(function (err) {
|
||||
t.ifError(err, 'no open() error (1)')
|
||||
t.is(db.status, 'open', 'is open')
|
||||
|
||||
db.open(assertAsync(function (err) {
|
||||
t.ifError(err, 'no open() error (2)')
|
||||
t.is(db.status, 'open', 'is open')
|
||||
}))
|
||||
|
||||
t.is(db.status, 'open', 'not reopening')
|
||||
db.on('open', t.fail.bind(t))
|
||||
assertAsync.end(t)
|
||||
}))
|
||||
|
||||
assertAsync.end(t)
|
||||
})
|
||||
|
||||
test('test database open if already opening (parallel)', assertAsync.ctx(function (t) {
|
||||
t.plan(7)
|
||||
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(assertAsync(function (err) {
|
||||
t.ifError(err, 'no open() error (1)')
|
||||
t.is(db.status, 'open')
|
||||
}))
|
||||
|
||||
db.open(assertAsync(function (err) {
|
||||
t.ifError(err, 'no open() error (2)')
|
||||
t.is(db.status, 'open')
|
||||
db.close(t.end.bind(t))
|
||||
}))
|
||||
|
||||
t.is(db.status, 'opening')
|
||||
}))
|
||||
|
||||
test('test database close if already closed', function (t) {
|
||||
t.plan(8)
|
||||
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open() error')
|
||||
|
||||
db.close(assertAsync(function (err) {
|
||||
t.ifError(err, 'no close() error (1)')
|
||||
t.is(db.status, 'closed', 'is closed')
|
||||
|
||||
db.close(assertAsync(function (err) {
|
||||
t.ifError(err, 'no close() error (2)')
|
||||
t.is(db.status, 'closed', 'is closed')
|
||||
}))
|
||||
|
||||
t.is(db.status, 'closed', 'is closed', 'not reclosing')
|
||||
db.on('closed', t.fail.bind(t))
|
||||
assertAsync.end(t)
|
||||
}))
|
||||
|
||||
assertAsync.end(t)
|
||||
})
|
||||
})
|
||||
|
||||
test('test database close if new', assertAsync.ctx(function (t) {
|
||||
t.plan(5)
|
||||
|
||||
const db = testCommon.factory()
|
||||
const expectedStatus = db.supports.deferredOpen ? 'opening' : 'closed'
|
||||
|
||||
t.is(db.status, expectedStatus, 'status ok')
|
||||
|
||||
db.close(assertAsync(function (err) {
|
||||
t.ifError(err, 'no close() error')
|
||||
t.is(db.status, 'closed', 'status ok')
|
||||
}))
|
||||
|
||||
t.is(db.status, expectedStatus, 'status unchanged')
|
||||
|
||||
if (!db.supports.deferredOpen) {
|
||||
db.on('closed', t.fail.bind(t, 'should not emit closed'))
|
||||
}
|
||||
}))
|
||||
|
||||
test('test database close on open event', function (t) {
|
||||
t.plan(5)
|
||||
|
||||
const db = testCommon.factory()
|
||||
const order = []
|
||||
|
||||
db.open(function (err) {
|
||||
order.push('A')
|
||||
t.is(err && err.code, 'LEVEL_DATABASE_NOT_OPEN', 'got open() error')
|
||||
t.is(db.status, 'closed', 'is closed')
|
||||
})
|
||||
|
||||
db.on('open', function () {
|
||||
// This wins from the (still in progress) open() call
|
||||
db.close(function (err) {
|
||||
order.push('B')
|
||||
t.same(order, ['A', 'closed event', 'B'], 'order is correct')
|
||||
t.ifError(err, 'no close() error')
|
||||
t.is(db.status, 'closed', 'is closed')
|
||||
})
|
||||
})
|
||||
|
||||
db.on('closed', () => { order.push('closed event') })
|
||||
})
|
||||
|
||||
test('test passive open()', async function (t) {
|
||||
t.plan(1)
|
||||
const db = testCommon.factory()
|
||||
await db.open({ passive: true }) // OK, already opening
|
||||
await db.close()
|
||||
await db.open({ passive: true }).catch(err => {
|
||||
t.is(err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
})
|
||||
await db.open()
|
||||
await db.open({ passive: true }) // OK, already open
|
||||
return db.close()
|
||||
})
|
||||
|
||||
test('test passive open(): ignored if set in constructor options', async function (t) {
|
||||
const db = testCommon.factory({ passive: true })
|
||||
await new Promise((resolve) => db.once('open', resolve))
|
||||
return db.close()
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.open(test, testCommon)
|
||||
}
|
113
node_modules/abstract-level/test/put-get-del-test.js
generated
vendored
Normal file
113
node_modules/abstract-level/test/put-get-del-test.js
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
'use strict'
|
||||
|
||||
const { verifyNotFoundError } = require('./util')
|
||||
const { Buffer } = require('buffer')
|
||||
|
||||
let db
|
||||
|
||||
function makeTest (test, type, key, value, expectedResult) {
|
||||
const hasExpectedResult = arguments.length === 5
|
||||
test('test put()/get()/del() with ' + type, function (t) {
|
||||
db.put(key, value, function (err) {
|
||||
t.error(err)
|
||||
db.get(key, function (err, _value) {
|
||||
t.error(err, 'no error, has key/value for `' + type + '`')
|
||||
|
||||
let result = _value
|
||||
|
||||
if (hasExpectedResult) {
|
||||
t.equal(result.toString(), expectedResult)
|
||||
} else {
|
||||
if (result != null) { result = _value.toString() }
|
||||
if (value != null) { value = value.toString() }
|
||||
t.equals(result, value)
|
||||
}
|
||||
db.del(key, function (err) {
|
||||
t.error(err, 'no error, deleted key/value for `' + type + '`')
|
||||
|
||||
let async = false
|
||||
|
||||
db.get(key, function (err, value) {
|
||||
t.ok(err, 'entry properly deleted')
|
||||
t.ok(verifyNotFoundError(err), 'correct error')
|
||||
t.is(value, undefined, 'value is undefined')
|
||||
t.ok(async, 'callback is asynchronous')
|
||||
t.end()
|
||||
})
|
||||
|
||||
async = true
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
exports.setUp = function (test, testCommon) {
|
||||
test('setUp db', function (t) {
|
||||
db = testCommon.factory()
|
||||
db.open(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.nonErrorKeys = function (test, testCommon) {
|
||||
// valid falsey keys
|
||||
makeTest(test, '`0` key', 0, 'foo 0')
|
||||
makeTest(test, 'empty string key', 0, 'foo')
|
||||
|
||||
// standard String key
|
||||
makeTest(
|
||||
test
|
||||
, 'long String key'
|
||||
, 'some long string that I\'m using as a key for this unit test, cross your fingers human, we\'re going in!'
|
||||
, 'foo'
|
||||
)
|
||||
|
||||
if (testCommon.supports.encodings.buffer) {
|
||||
makeTest(test, 'Buffer key', Buffer.from('0080c0ff', 'hex'), 'foo')
|
||||
makeTest(test, 'empty Buffer key', Buffer.alloc(0), 'foo')
|
||||
}
|
||||
|
||||
// non-empty Array as a value
|
||||
makeTest(test, 'Array value', 'foo', [1, 2, 3, 4])
|
||||
}
|
||||
|
||||
exports.nonErrorValues = function (test, testCommon) {
|
||||
// valid falsey values
|
||||
makeTest(test, '`false` value', 'foo false', false)
|
||||
makeTest(test, '`0` value', 'foo 0', 0)
|
||||
makeTest(test, '`NaN` value', 'foo NaN', NaN)
|
||||
|
||||
// all of the following result in an empty-string value:
|
||||
makeTest(test, 'empty String value', 'foo', '', '')
|
||||
makeTest(test, 'empty Buffer value', 'foo', Buffer.alloc(0), '')
|
||||
makeTest(test, 'empty Array value', 'foo', [], '')
|
||||
|
||||
// String value
|
||||
makeTest(
|
||||
test
|
||||
, 'long String value'
|
||||
, 'foo'
|
||||
, 'some long string that I\'m using as a key for this unit test, cross your fingers human, we\'re going in!'
|
||||
)
|
||||
|
||||
// Buffer value
|
||||
if (testCommon.supports.encodings.buffer) {
|
||||
makeTest(test, 'Buffer value', 'foo', Buffer.from('0080c0ff', 'hex'))
|
||||
}
|
||||
|
||||
// non-empty Array as a key
|
||||
makeTest(test, 'Array key', [1, 2, 3, 4], 'foo')
|
||||
}
|
||||
|
||||
exports.tearDown = function (test, testCommon) {
|
||||
test('tearDown', function (t) {
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.setUp(test, testCommon)
|
||||
exports.nonErrorKeys(test, testCommon)
|
||||
exports.nonErrorValues(test, testCommon)
|
||||
exports.tearDown(test, testCommon)
|
||||
}
|
131
node_modules/abstract-level/test/put-test.js
generated
vendored
Normal file
131
node_modules/abstract-level/test/put-test.js
generated
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
'use strict'
|
||||
|
||||
const { assertAsync, illegalKeys, illegalValues } = require('./util')
|
||||
|
||||
let db
|
||||
|
||||
exports.setUp = function (test, testCommon) {
|
||||
test('setUp db', function (t) {
|
||||
db = testCommon.factory()
|
||||
db.open(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.args = function (test, testCommon) {
|
||||
test('test put() with illegal keys', assertAsync.ctx(function (t) {
|
||||
t.plan(illegalKeys.length * 5)
|
||||
|
||||
for (const { name, key } of illegalKeys) {
|
||||
db.put(key, 'value', assertAsync(function (err) {
|
||||
t.ok(err instanceof Error, name + ' - is Error (callback)')
|
||||
t.is(err && err.code, 'LEVEL_INVALID_KEY', name + ' - correct error code (callback)')
|
||||
}))
|
||||
|
||||
db.put(key, 'value').catch(function (err) {
|
||||
t.ok(err instanceof Error, name + ' - is Error (promise)')
|
||||
t.is(err.code, 'LEVEL_INVALID_KEY', name + ' - correct error code (promise)')
|
||||
})
|
||||
}
|
||||
}))
|
||||
|
||||
test('test put() with illegal values', assertAsync.ctx(function (t) {
|
||||
t.plan(illegalValues.length * 5)
|
||||
|
||||
for (const { name, value } of illegalValues) {
|
||||
db.put('key', value, assertAsync(function (err) {
|
||||
t.ok(err instanceof Error, name + '- is Error (callback)')
|
||||
t.is(err && err.code, 'LEVEL_INVALID_VALUE', name + ' - correct error code (callback)')
|
||||
}))
|
||||
|
||||
db.put('key', value).catch(function (err) {
|
||||
t.ok(err instanceof Error, name + ' - is Error (promise)')
|
||||
t.is(err.code, 'LEVEL_INVALID_VALUE', name + ' - correct error code (promise)')
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
exports.put = function (test, testCommon) {
|
||||
test('test simple put()', assertAsync.ctx(function (t) {
|
||||
t.plan(7)
|
||||
|
||||
db.put('foo', 'bar', assertAsync(function (err) {
|
||||
t.ifError(err, 'no put() error')
|
||||
|
||||
db.get('foo', function (err, value) {
|
||||
t.ifError(err, 'no get() error')
|
||||
t.is(value, 'bar')
|
||||
|
||||
db.put('foo', 'new', function (err) {
|
||||
t.ifError(err, 'no put() error')
|
||||
|
||||
db.get('foo', function (err, value) {
|
||||
t.ifError(err, 'no get() error')
|
||||
t.is(value, 'new', 'value was overwritten')
|
||||
})
|
||||
})
|
||||
})
|
||||
}))
|
||||
}))
|
||||
|
||||
test('test simple put() with promise', async function (t) {
|
||||
await db.put('foo2', 'bar')
|
||||
t.is(await db.get('foo2'), 'bar')
|
||||
})
|
||||
|
||||
test('test deferred put()', assertAsync.ctx(function (t) {
|
||||
t.plan(5)
|
||||
|
||||
const db = testCommon.factory()
|
||||
|
||||
db.put('foo', 'bar', assertAsync(function (err) {
|
||||
t.ifError(err, 'no put() error')
|
||||
|
||||
db.get('foo', { valueEncoding: 'utf8' }, function (err, value) {
|
||||
t.ifError(err, 'no get() error')
|
||||
t.is(value, 'bar', 'value is ok')
|
||||
db.close(t.ifError.bind(t))
|
||||
})
|
||||
}))
|
||||
}))
|
||||
|
||||
test('test deferred put() with promise', async function (t) {
|
||||
const db = testCommon.factory()
|
||||
await db.put('foo', 'bar')
|
||||
t.is(await db.get('foo', { valueEncoding: 'utf8' }), 'bar', 'value is ok')
|
||||
return db.close()
|
||||
})
|
||||
}
|
||||
|
||||
exports.events = function (test, testCommon) {
|
||||
test('test put() emits put event', async function (t) {
|
||||
t.plan(3)
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
|
||||
t.ok(db.supports.events.put)
|
||||
|
||||
db.on('put', function (key, value) {
|
||||
t.is(key, 123)
|
||||
t.is(value, 'b')
|
||||
})
|
||||
|
||||
await db.put(123, 'b')
|
||||
await db.close()
|
||||
})
|
||||
}
|
||||
|
||||
exports.tearDown = function (test, testCommon) {
|
||||
test('tearDown', function (t) {
|
||||
db.close(t.end.bind(t))
|
||||
})
|
||||
}
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
exports.setUp(test, testCommon)
|
||||
exports.args(test, testCommon)
|
||||
exports.put(test, testCommon)
|
||||
exports.events(test, testCommon)
|
||||
exports.tearDown(test, testCommon)
|
||||
}
|
1080
node_modules/abstract-level/test/self.js
generated
vendored
Normal file
1080
node_modules/abstract-level/test/self.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
263
node_modules/abstract-level/test/self/abstract-iterator-test.js
generated
vendored
Normal file
263
node_modules/abstract-level/test/self/abstract-iterator-test.js
generated
vendored
Normal file
@ -0,0 +1,263 @@
|
||||
'use strict'
|
||||
|
||||
const test = require('tape')
|
||||
const { AbstractLevel, AbstractIterator, AbstractKeyIterator, AbstractValueIterator } = require('../..')
|
||||
|
||||
const testCommon = require('../common')({
|
||||
test,
|
||||
factory: function () {
|
||||
return new AbstractLevel({ encodings: { utf8: true } })
|
||||
}
|
||||
})
|
||||
|
||||
for (const Ctor of [AbstractIterator, AbstractKeyIterator, AbstractValueIterator]) {
|
||||
test(`test ${Ctor.name} extensibility`, function (t) {
|
||||
const Test = class TestIterator extends Ctor {}
|
||||
const db = testCommon.factory()
|
||||
const test = new Test(db, {})
|
||||
t.ok(test.db === db, 'instance has db reference')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test(`${Ctor.name} throws on invalid db argument`, function (t) {
|
||||
t.plan(4 * 2)
|
||||
|
||||
for (const args of [[], [null], [undefined], 'foo']) {
|
||||
const hint = args[0] === null ? 'null' : typeof args[0]
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line no-new
|
||||
new Ctor(...args)
|
||||
} catch (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err.message, 'The first argument must be an abstract-level database, received ' + hint)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test(`${Ctor.name} throws on invalid options argument`, function (t) {
|
||||
t.plan(4 * 2)
|
||||
|
||||
for (const args of [[], [null], [undefined], 'foo']) {
|
||||
try {
|
||||
// eslint-disable-next-line no-new
|
||||
new Ctor({}, ...args)
|
||||
} catch (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err.message, 'The second argument must be an options object')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test(`${Ctor.name}.next() extensibility`, async function (t) {
|
||||
t.plan(3)
|
||||
|
||||
class TestIterator extends Ctor {
|
||||
_next (callback) {
|
||||
t.is(this, it, 'thisArg on _next() was correct')
|
||||
t.is(arguments.length, 1, 'got one argument')
|
||||
t.is(typeof callback, 'function', 'got a callback function')
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
const it = new TestIterator(db, {})
|
||||
await it.next()
|
||||
await db.close()
|
||||
})
|
||||
|
||||
test(`${Ctor.name}.next() throws on invalid callback argument`, async function (t) {
|
||||
t.plan(3 * 2)
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
|
||||
for (const invalid of [{}, null, 'foo']) {
|
||||
const it = new Ctor(db, {})
|
||||
|
||||
try {
|
||||
it.next(invalid)
|
||||
} catch (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err.message, 'Callback must be a function')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test(`${Ctor.name}.nextv() extensibility`, async function (t) {
|
||||
t.plan(5 * 2)
|
||||
|
||||
class TestIterator extends Ctor {
|
||||
_nextv (size, options, callback) {
|
||||
t.is(this, it, 'thisArg on _nextv() was correct')
|
||||
t.is(arguments.length, 3, 'got 3 arguments')
|
||||
t.is(size, 100)
|
||||
t.same(options, {}, 'empty options')
|
||||
t.is(typeof callback, 'function', 'got a callback function')
|
||||
this.nextTick(callback, null, [])
|
||||
}
|
||||
}
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
const it = new TestIterator(db, {})
|
||||
await it.nextv(100)
|
||||
await it.nextv(100, {})
|
||||
await db.close()
|
||||
})
|
||||
|
||||
test(`${Ctor.name}.nextv() extensibility (options)`, async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
class TestIterator extends Ctor {
|
||||
_nextv (size, options, callback) {
|
||||
t.is(size, 100)
|
||||
t.same(options, { foo: 123 }, 'got options')
|
||||
this.nextTick(callback, null, [])
|
||||
}
|
||||
}
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
const it = new TestIterator(db, {})
|
||||
await it.nextv(100, { foo: 123 })
|
||||
await db.close()
|
||||
})
|
||||
|
||||
test(`${Ctor.name}.nextv() throws on invalid callback argument`, async function (t) {
|
||||
t.plan(3 * 2)
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
|
||||
for (const invalid of [{}, null, 'foo']) {
|
||||
const it = new Ctor(db, {})
|
||||
|
||||
try {
|
||||
it.nextv(100, {}, invalid)
|
||||
} catch (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err.message, 'Callback must be a function')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test(`${Ctor.name}.all() extensibility`, async function (t) {
|
||||
t.plan(2 * 4)
|
||||
|
||||
for (const args of [[], [{}]]) {
|
||||
class TestIterator extends Ctor {
|
||||
_all (options, callback) {
|
||||
t.is(this, it, 'thisArg on _all() was correct')
|
||||
t.is(arguments.length, 2, 'got 2 arguments')
|
||||
t.same(options, {}, 'empty options')
|
||||
t.is(typeof callback, 'function', 'got a callback function')
|
||||
this.nextTick(callback, null, [])
|
||||
}
|
||||
}
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
const it = new TestIterator(db, {})
|
||||
await it.all(...args)
|
||||
await db.close()
|
||||
}
|
||||
})
|
||||
|
||||
test(`${Ctor.name}.all() extensibility (options)`, async function (t) {
|
||||
t.plan(1)
|
||||
|
||||
class TestIterator extends Ctor {
|
||||
_all (options, callback) {
|
||||
t.same(options, { foo: 123 }, 'got options')
|
||||
this.nextTick(callback, null, [])
|
||||
}
|
||||
}
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
const it = new TestIterator(db, {})
|
||||
await it.all({ foo: 123 })
|
||||
await db.close()
|
||||
})
|
||||
|
||||
test(`${Ctor.name}.all() throws on invalid callback argument`, async function (t) {
|
||||
t.plan(3 * 2)
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
|
||||
for (const invalid of [{}, null, 'foo']) {
|
||||
const it = new Ctor(db, {})
|
||||
|
||||
try {
|
||||
it.all({}, invalid)
|
||||
} catch (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err.message, 'Callback must be a function')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test(`${Ctor.name}.close() extensibility`, async function (t) {
|
||||
t.plan(3)
|
||||
|
||||
class TestIterator extends Ctor {
|
||||
_close (callback) {
|
||||
t.is(this, it, 'thisArg on _close() was correct')
|
||||
t.is(arguments.length, 1, 'got one argument')
|
||||
t.is(typeof callback, 'function', 'got a callback function')
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
const it = new TestIterator(db, {})
|
||||
await it.close()
|
||||
await db.close()
|
||||
})
|
||||
|
||||
test(`${Ctor.name}.close() throws on invalid callback argument`, async function (t) {
|
||||
t.plan(3 * 2)
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
|
||||
for (const invalid of [{}, null, 'foo']) {
|
||||
const it = new Ctor(db, {})
|
||||
|
||||
try {
|
||||
it.close(invalid)
|
||||
} catch (err) {
|
||||
t.is(err.name, 'TypeError')
|
||||
t.is(err.message, 'Callback must be a function')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
test('AbstractIterator throws when accessing legacy properties', async function (t) {
|
||||
t.plan(3 * 2)
|
||||
|
||||
const db = testCommon.factory()
|
||||
await db.open()
|
||||
const it = new AbstractIterator(db, {})
|
||||
|
||||
for (const k of ['_ended property', '_nexting property', '_end method']) {
|
||||
try {
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
it[k.split(' ')[0]]
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_LEGACY')
|
||||
}
|
||||
|
||||
try {
|
||||
it[k.split(' ')[0]] = 123
|
||||
} catch (err) {
|
||||
t.is(err.code, 'LEVEL_LEGACY')
|
||||
}
|
||||
}
|
||||
})
|
213
node_modules/abstract-level/test/self/async-iterator-test.js
generated
vendored
Normal file
213
node_modules/abstract-level/test/self/async-iterator-test.js
generated
vendored
Normal file
@ -0,0 +1,213 @@
|
||||
'use strict'
|
||||
|
||||
const test = require('tape')
|
||||
const { AbstractLevel, AbstractIterator } = require('../..')
|
||||
const { DeferredIterator, DeferredKeyIterator, DeferredValueIterator } = require('../../lib/deferred-iterator')
|
||||
|
||||
function withIterator (methods) {
|
||||
class TestIterator extends AbstractIterator { }
|
||||
|
||||
for (const k in methods) {
|
||||
TestIterator.prototype[k] = methods[k]
|
||||
}
|
||||
|
||||
class Test extends AbstractLevel {
|
||||
_iterator (options) {
|
||||
return new TestIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
return new Test({ encodings: { utf8: true } })
|
||||
}
|
||||
|
||||
for (const mode of ['iterator', 'keys', 'values']) {
|
||||
for (const type of ['explicit', 'deferred']) {
|
||||
const verify = function (t, db, it) {
|
||||
t.is(db.status, type === 'explicit' ? 'open' : 'opening')
|
||||
|
||||
if (type === 'explicit') {
|
||||
t.is(
|
||||
it.constructor.name,
|
||||
mode === 'iterator' ? 'TestIterator' : mode === 'keys' ? 'DefaultKeyIterator' : 'DefaultValueIterator'
|
||||
)
|
||||
} else {
|
||||
t.is(
|
||||
it.constructor,
|
||||
mode === 'iterator' ? DeferredIterator : mode === 'keys' ? DeferredKeyIterator : DeferredValueIterator
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
test(`for await...of ${mode}() (${type} open)`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const input = [{ key: '1', value: '1' }, { key: '2', value: '2' }]
|
||||
const output = []
|
||||
|
||||
const db = withIterator({
|
||||
_next (callback) {
|
||||
const { key, value } = input[n++] || []
|
||||
this.nextTick(callback, null, key, value)
|
||||
},
|
||||
|
||||
_close (callback) {
|
||||
this.nextTick(function () {
|
||||
closed = true
|
||||
callback()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if (type === 'explicit') await db.open()
|
||||
const it = db[mode]({ keyEncoding: 'utf8', valueEncoding: 'utf8' })
|
||||
verify(t, db, it)
|
||||
|
||||
let n = 0
|
||||
let closed = false
|
||||
|
||||
for await (const item of it) {
|
||||
output.push(item)
|
||||
}
|
||||
|
||||
t.same(output, input.map(x => mode === 'iterator' ? [x.key, x.value] : mode === 'keys' ? x.key : x.value))
|
||||
t.ok(closed, 'closed')
|
||||
})
|
||||
|
||||
test(`for await...of ${mode}() closes on user error (${type} open)`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = withIterator({
|
||||
_next (callback) {
|
||||
this.nextTick(callback, null, n.toString(), n.toString())
|
||||
if (n++ > 10) throw new Error('Infinite loop')
|
||||
},
|
||||
|
||||
_close (callback) {
|
||||
this.nextTick(function () {
|
||||
closed = true
|
||||
callback(new Error('close error'))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if (type === 'explicit') await db.open()
|
||||
const it = db[mode]()
|
||||
verify(t, db, it)
|
||||
|
||||
let n = 0
|
||||
let closed = false
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line no-unused-vars, no-unreachable-loop
|
||||
for await (const kv of it) {
|
||||
throw new Error('user error')
|
||||
}
|
||||
} catch (err) {
|
||||
t.is(err.message, 'user error')
|
||||
t.ok(closed, 'closed')
|
||||
}
|
||||
})
|
||||
|
||||
test(`for await...of ${mode}() closes on iterator error (${type} open)`, async function (t) {
|
||||
t.plan(5)
|
||||
|
||||
const db = withIterator({
|
||||
_next (callback) {
|
||||
t.pass('nexted')
|
||||
this.nextTick(callback, new Error('iterator error'))
|
||||
},
|
||||
|
||||
_close (callback) {
|
||||
this.nextTick(function () {
|
||||
closed = true
|
||||
callback()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if (type === 'explicit') await db.open()
|
||||
const it = db[mode]()
|
||||
verify(t, db, it)
|
||||
|
||||
let closed = false
|
||||
|
||||
try {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
for await (const kv of it) {
|
||||
t.fail('should not yield items')
|
||||
}
|
||||
} catch (err) {
|
||||
t.is(err.message, 'iterator error')
|
||||
t.ok(closed, 'closed')
|
||||
}
|
||||
})
|
||||
|
||||
test(`for await...of ${mode}() closes on user break (${type} open)`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = withIterator({
|
||||
_next (callback) {
|
||||
this.nextTick(callback, null, n.toString(), n.toString())
|
||||
if (n++ > 10) throw new Error('Infinite loop')
|
||||
},
|
||||
|
||||
_close (callback) {
|
||||
this.nextTick(function () {
|
||||
closed = true
|
||||
callback()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if (type === 'explicit') await db.open()
|
||||
const it = db[mode]()
|
||||
verify(t, db, it)
|
||||
|
||||
let n = 0
|
||||
let closed = false
|
||||
|
||||
// eslint-disable-next-line no-unused-vars, no-unreachable-loop
|
||||
for await (const kv of it) {
|
||||
t.pass('got a chance to break')
|
||||
break
|
||||
}
|
||||
|
||||
t.ok(closed, 'closed')
|
||||
})
|
||||
|
||||
test(`for await...of ${mode}() closes on user return (${type} open)`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = withIterator({
|
||||
_next (callback) {
|
||||
this.nextTick(callback, null, n.toString(), n.toString())
|
||||
if (n++ > 10) throw new Error('Infinite loop')
|
||||
},
|
||||
|
||||
_close (callback) {
|
||||
this.nextTick(function () {
|
||||
closed = true
|
||||
callback()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if (type === 'explicit') await db.open()
|
||||
const it = db[mode]()
|
||||
verify(t, db, it)
|
||||
|
||||
let n = 0
|
||||
let closed = false
|
||||
|
||||
await (async () => {
|
||||
// eslint-disable-next-line no-unused-vars, no-unreachable-loop
|
||||
for await (const kv of it) {
|
||||
t.pass('got a chance to return')
|
||||
return
|
||||
}
|
||||
})()
|
||||
|
||||
t.ok(closed, 'closed')
|
||||
})
|
||||
}
|
||||
}
|
75
node_modules/abstract-level/test/self/attach-resource-test.js
generated
vendored
Normal file
75
node_modules/abstract-level/test/self/attach-resource-test.js
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
'use strict'
|
||||
|
||||
const test = require('tape')
|
||||
const { mockLevel } = require('../util')
|
||||
const nextTick = require('../../lib/next-tick')
|
||||
|
||||
test('resource must be an object with a close() method', function (t) {
|
||||
t.plan(5)
|
||||
|
||||
const db = mockLevel()
|
||||
|
||||
for (const invalid of [null, undefined, {}, { close: 123 }]) {
|
||||
try {
|
||||
db.attachResource(invalid)
|
||||
} catch (err) {
|
||||
t.is(err && err.message, 'The first argument must be a resource object')
|
||||
}
|
||||
}
|
||||
|
||||
db.close(t.ifError.bind(t))
|
||||
})
|
||||
|
||||
test('resource is closed on failed open', function (t) {
|
||||
t.plan(2)
|
||||
|
||||
const db = mockLevel({
|
||||
_open: function (options, callback) {
|
||||
t.pass('opened')
|
||||
this.nextTick(callback, new Error('_open error'))
|
||||
}
|
||||
})
|
||||
|
||||
const resource = {
|
||||
close: function (cb) {
|
||||
// Note: resource shouldn't care about db.status
|
||||
t.pass('closed')
|
||||
nextTick(cb)
|
||||
}
|
||||
}
|
||||
|
||||
db.attachResource(resource)
|
||||
})
|
||||
|
||||
test('resource is closed on db.close()', function (t) {
|
||||
t.plan(2)
|
||||
|
||||
const db = mockLevel()
|
||||
|
||||
const resource = {
|
||||
close: function (cb) {
|
||||
// Note: resource shouldn't care about db.status
|
||||
t.pass('closed')
|
||||
nextTick(cb)
|
||||
}
|
||||
}
|
||||
|
||||
db.attachResource(resource)
|
||||
db.close(t.ifError.bind(t))
|
||||
})
|
||||
|
||||
test('resource is not closed on db.close() if detached', function (t) {
|
||||
t.plan(1)
|
||||
|
||||
const db = mockLevel()
|
||||
|
||||
const resource = {
|
||||
close: function (cb) {
|
||||
t.fail('should not be called')
|
||||
}
|
||||
}
|
||||
|
||||
db.attachResource(resource)
|
||||
db.detachResource(resource)
|
||||
db.close(t.ifError.bind(t))
|
||||
})
|
90
node_modules/abstract-level/test/self/defer-test.js
generated
vendored
Normal file
90
node_modules/abstract-level/test/self/defer-test.js
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
'use strict'
|
||||
|
||||
const test = require('tape')
|
||||
const { mockLevel } = require('../util')
|
||||
|
||||
test('defer() requires valid function argument', function (t) {
|
||||
t.plan(7)
|
||||
|
||||
const db = mockLevel()
|
||||
|
||||
for (const invalid of [123, true, false, null, undefined, {}]) {
|
||||
try {
|
||||
db.defer(invalid)
|
||||
} catch (err) {
|
||||
t.is(err.message, 'The first argument must be a function')
|
||||
}
|
||||
}
|
||||
|
||||
db.close(t.ifError.bind(t))
|
||||
})
|
||||
|
||||
test('defer() custom operation', function (t) {
|
||||
t.plan(6)
|
||||
|
||||
const db = mockLevel({
|
||||
custom (arg, callback) {
|
||||
if (this.status === 'opening') {
|
||||
t.is(arg, 123)
|
||||
this.defer(() => this.custom(456, callback))
|
||||
} else {
|
||||
t.is(db.status, 'open')
|
||||
t.is(arg, 456)
|
||||
this.nextTick(callback, null, 987)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
db.custom(123, function (err, result) {
|
||||
t.ifError(err, 'no custom() error')
|
||||
t.is(result, 987, 'result ok')
|
||||
|
||||
db.close(t.ifError.bind(t))
|
||||
})
|
||||
})
|
||||
|
||||
test('defer() custom operation with failed open', function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = mockLevel({
|
||||
_open (options, callback) {
|
||||
t.pass('opened')
|
||||
this.nextTick(callback, new Error('_open error'))
|
||||
},
|
||||
custom (arg, callback) {
|
||||
if (this.status === 'opening') {
|
||||
this.defer(() => this.custom(arg, callback))
|
||||
} else {
|
||||
t.is(db.status, 'closed')
|
||||
this.nextTick(callback, new Error('Database is not open (x)'))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
db.custom(123, function (err, result) {
|
||||
t.is(err && err.message, 'Database is not open (x)')
|
||||
t.is(result, undefined, 'result ok')
|
||||
})
|
||||
})
|
||||
|
||||
test('defer() can drop custom synchronous operation', function (t) {
|
||||
t.plan(3)
|
||||
|
||||
const db = mockLevel({
|
||||
_open (options, callback) {
|
||||
t.pass('opened')
|
||||
this.nextTick(callback, new Error('_open error'))
|
||||
},
|
||||
custom (arg) {
|
||||
if (this.status === 'opening') {
|
||||
this.defer(() => this.custom(arg * 2))
|
||||
} else {
|
||||
// Handling other states is a userland responsibility
|
||||
t.is(db.status, 'closed')
|
||||
t.is(arg, 246)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
db.custom(123)
|
||||
})
|
98
node_modules/abstract-level/test/self/deferred-chained-batch-test.js
generated
vendored
Normal file
98
node_modules/abstract-level/test/self/deferred-chained-batch-test.js
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
'use strict'
|
||||
|
||||
const test = require('tape')
|
||||
const { mockLevel } = require('../util')
|
||||
const { DefaultChainedBatch } = require('../../lib/default-chained-batch')
|
||||
const identity = (v) => v
|
||||
|
||||
// NOTE: adapted from deferred-leveldown
|
||||
test('deferred chained batch encodes once', function (t) {
|
||||
t.plan(9)
|
||||
|
||||
let called = false
|
||||
|
||||
const keyEncoding = {
|
||||
format: 'utf8',
|
||||
encode (key) {
|
||||
t.is(called, false, 'not yet called')
|
||||
t.is(key, 'foo')
|
||||
return key.toUpperCase()
|
||||
},
|
||||
decode: identity
|
||||
}
|
||||
|
||||
const valueEncoding = {
|
||||
format: 'utf8',
|
||||
encode (value) {
|
||||
t.is(called, false, 'not yet called')
|
||||
t.is(value, 'bar')
|
||||
return value.toUpperCase()
|
||||
},
|
||||
decode: identity
|
||||
}
|
||||
|
||||
const db = mockLevel({
|
||||
_batch: function (array, options, callback) {
|
||||
called = true
|
||||
t.is(array[0] && array[0].key, 'FOO')
|
||||
t.is(array[0] && array[0].value, 'BAR')
|
||||
this.nextTick(callback)
|
||||
},
|
||||
_open: function (options, callback) {
|
||||
t.is(called, false, 'not yet called')
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}, { encodings: { utf8: true } }, {
|
||||
keyEncoding,
|
||||
valueEncoding
|
||||
})
|
||||
|
||||
db.once('open', function () {
|
||||
t.is(called, true, 'called')
|
||||
})
|
||||
|
||||
db.batch().put('foo', 'bar').write(function (err) {
|
||||
t.ifError(err, 'no write() error')
|
||||
})
|
||||
})
|
||||
|
||||
test('deferred chained batch is closed upon failed open', function (t) {
|
||||
t.plan(6)
|
||||
|
||||
const db = mockLevel({
|
||||
_open (options, callback) {
|
||||
t.pass('opening')
|
||||
this.nextTick(callback, new Error('_open error'))
|
||||
},
|
||||
_batch () {
|
||||
t.fail('should not be called')
|
||||
}
|
||||
})
|
||||
|
||||
const batch = db.batch()
|
||||
t.ok(batch instanceof DefaultChainedBatch)
|
||||
|
||||
batch.put('foo', 'bar')
|
||||
batch.del('123')
|
||||
|
||||
batch.write(function (err) {
|
||||
t.is(err && err.code, 'LEVEL_BATCH_NOT_OPEN')
|
||||
|
||||
// Should account for userland code that ignores errors
|
||||
try {
|
||||
batch.put('beep', 'boop')
|
||||
} catch (err) {
|
||||
t.is(err && err.code, 'LEVEL_BATCH_NOT_OPEN')
|
||||
}
|
||||
|
||||
try {
|
||||
batch.del('456')
|
||||
} catch (err) {
|
||||
t.is(err && err.code, 'LEVEL_BATCH_NOT_OPEN')
|
||||
}
|
||||
|
||||
batch.write(function (err) {
|
||||
t.is(err && err.code, 'LEVEL_BATCH_NOT_OPEN')
|
||||
})
|
||||
})
|
||||
})
|
298
node_modules/abstract-level/test/self/deferred-iterator-test.js
generated
vendored
Normal file
298
node_modules/abstract-level/test/self/deferred-iterator-test.js
generated
vendored
Normal file
@ -0,0 +1,298 @@
|
||||
'use strict'
|
||||
|
||||
const test = require('tape')
|
||||
const { DeferredIterator, DeferredKeyIterator, DeferredValueIterator } = require('../../lib/deferred-iterator')
|
||||
const { AbstractIterator, AbstractKeyIterator, AbstractValueIterator } = require('../..')
|
||||
const { mockLevel } = require('../util')
|
||||
const noop = () => {}
|
||||
const identity = (v) => v
|
||||
|
||||
for (const mode of ['iterator', 'keys', 'values']) {
|
||||
const RealCtor = mode === 'iterator' ? AbstractIterator : mode === 'keys' ? AbstractKeyIterator : AbstractValueIterator
|
||||
const DeferredCtor = mode === 'iterator' ? DeferredIterator : mode === 'keys' ? DeferredKeyIterator : DeferredValueIterator
|
||||
const nextArgs = mode === 'iterator' ? ['key', 'value'] : mode === 'keys' ? ['key'] : ['value']
|
||||
const privateMethod = '_' + mode
|
||||
const publicMethod = mode
|
||||
|
||||
// NOTE: adapted from deferred-leveldown
|
||||
test(`deferred ${mode}()`, function (t) {
|
||||
t.plan(8)
|
||||
|
||||
const keyEncoding = {
|
||||
format: 'utf8',
|
||||
encode (key) {
|
||||
t.is(key, 'foo', 'encoding got key')
|
||||
return key.toUpperCase()
|
||||
},
|
||||
decode: identity
|
||||
}
|
||||
|
||||
class MockIterator extends RealCtor {
|
||||
_next (cb) {
|
||||
this.nextTick(cb, null, ...nextArgs)
|
||||
}
|
||||
|
||||
_close (cb) {
|
||||
this.nextTick(cb)
|
||||
}
|
||||
}
|
||||
|
||||
const db = mockLevel({
|
||||
[privateMethod]: function (options) {
|
||||
t.is(options.gt, 'FOO', 'got encoded range option')
|
||||
return new MockIterator(this, options)
|
||||
},
|
||||
_open: function (options, callback) {
|
||||
t.pass('opened')
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}, { encodings: { utf8: true } }, {
|
||||
keyEncoding
|
||||
})
|
||||
|
||||
const it = db[publicMethod]({ gt: 'foo' })
|
||||
t.ok(it instanceof DeferredCtor, 'is deferred')
|
||||
|
||||
let nextFirst = false
|
||||
|
||||
it.next(function (err, ...rest) {
|
||||
nextFirst = true
|
||||
t.error(err, 'no next() error')
|
||||
t.same(rest, nextArgs)
|
||||
})
|
||||
|
||||
it.close(function (err) {
|
||||
t.error(err, 'no close() error')
|
||||
t.ok(nextFirst)
|
||||
})
|
||||
})
|
||||
|
||||
// NOTE: adapted from deferred-leveldown
|
||||
test(`deferred ${mode}(): non-deferred operations`, function (t) {
|
||||
t.plan(6)
|
||||
|
||||
class MockIterator extends RealCtor {
|
||||
_seek (target) {
|
||||
t.is(target, '123')
|
||||
}
|
||||
|
||||
_next (cb) {
|
||||
this.nextTick(cb, null, ...nextArgs)
|
||||
}
|
||||
}
|
||||
|
||||
const db = mockLevel({
|
||||
[privateMethod]: function (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
})
|
||||
|
||||
db.open(function (err) {
|
||||
t.error(err, 'no open() error')
|
||||
|
||||
it.seek(123)
|
||||
it.next(function (err, ...rest) {
|
||||
t.error(err, 'no next() error')
|
||||
t.same(rest, nextArgs)
|
||||
|
||||
it.close(function (err) {
|
||||
t.error(err, 'no close() error')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const it = db[publicMethod]({ gt: 'foo' })
|
||||
t.ok(it instanceof DeferredCtor)
|
||||
})
|
||||
|
||||
// NOTE: adapted from deferred-leveldown
|
||||
test(`deferred ${mode}(): iterators are created in order`, function (t) {
|
||||
t.plan(6)
|
||||
|
||||
const order1 = []
|
||||
const order2 = []
|
||||
|
||||
class MockIterator extends RealCtor {}
|
||||
|
||||
function db (order) {
|
||||
return mockLevel({
|
||||
[privateMethod]: function (options) {
|
||||
order.push('iterator created')
|
||||
return new MockIterator(this, options)
|
||||
},
|
||||
_put: function (key, value, options, callback) {
|
||||
order.push('put')
|
||||
},
|
||||
_open: function (options, callback) {
|
||||
this.nextTick(callback)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const db1 = db(order1)
|
||||
const db2 = db(order2)
|
||||
|
||||
db1.open(function (err) {
|
||||
t.error(err, 'no error')
|
||||
t.same(order1, ['iterator created', 'put'])
|
||||
})
|
||||
|
||||
db2.open(function (err) {
|
||||
t.error(err, 'no error')
|
||||
t.same(order2, ['put', 'iterator created'])
|
||||
})
|
||||
|
||||
t.ok(db1[publicMethod]() instanceof DeferredCtor)
|
||||
db1.put('key', 'value', noop)
|
||||
|
||||
db2.put('key', 'value', noop)
|
||||
t.ok(db2[publicMethod]() instanceof DeferredCtor)
|
||||
})
|
||||
|
||||
for (const method of ['next', 'nextv', 'all']) {
|
||||
test(`deferred ${mode}(): closed upon failed open, verified by ${method}()`, function (t) {
|
||||
t.plan(5)
|
||||
|
||||
const db = mockLevel({
|
||||
_open (options, callback) {
|
||||
t.pass('opening')
|
||||
this.nextTick(callback, new Error('_open error'))
|
||||
},
|
||||
_iterator () {
|
||||
t.fail('should not be called')
|
||||
},
|
||||
[privateMethod] () {
|
||||
t.fail('should not be called')
|
||||
}
|
||||
})
|
||||
|
||||
const it = db[publicMethod]()
|
||||
t.ok(it instanceof DeferredCtor)
|
||||
|
||||
const original = it._close
|
||||
it._close = function (...args) {
|
||||
t.pass('closed')
|
||||
return original.call(this, ...args)
|
||||
}
|
||||
|
||||
verifyClosed(t, it, method, () => {})
|
||||
})
|
||||
|
||||
test(`deferred ${mode}(): deferred and real iterators are closed on db.close(), verified by ${method}()`, function (t) {
|
||||
t.plan(10)
|
||||
|
||||
class MockIterator extends RealCtor {
|
||||
_close (callback) {
|
||||
t.pass('closed')
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}
|
||||
|
||||
const db = mockLevel({
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
})
|
||||
|
||||
const it = db[publicMethod]()
|
||||
t.ok(it instanceof DeferredCtor)
|
||||
|
||||
const original = it._close
|
||||
it._close = function (...args) {
|
||||
t.pass('closed')
|
||||
return original.call(this, ...args)
|
||||
}
|
||||
|
||||
db.close(function (err) {
|
||||
t.ifError(err, 'no close() error')
|
||||
|
||||
verifyClosed(t, it, method, function () {
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open() error')
|
||||
|
||||
// Should still be closed
|
||||
verifyClosed(t, it, method, function () {
|
||||
db.close(t.ifError.bind(t))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
test(`deferred ${mode}(): deferred and real iterators are detached on db.close()`, function (t) {
|
||||
t.plan(4)
|
||||
|
||||
class MockIterator extends RealCtor {}
|
||||
|
||||
let real
|
||||
const db = mockLevel({
|
||||
[privateMethod] (options) {
|
||||
real = new MockIterator(this, options)
|
||||
return real
|
||||
}
|
||||
})
|
||||
|
||||
const it = db[publicMethod]()
|
||||
t.ok(it instanceof DeferredCtor)
|
||||
|
||||
db.close(function (err) {
|
||||
t.ifError(err, 'no close() error')
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open() error')
|
||||
|
||||
it.close = real.close = it._close = real._close = function () {
|
||||
t.fail('should not be called')
|
||||
}
|
||||
|
||||
db.close(t.ifError.bind(t))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test(`deferred ${mode}(): defers underlying close()`, function (t) {
|
||||
t.plan(3)
|
||||
|
||||
class MockIterator extends RealCtor {
|
||||
_close (callback) {
|
||||
order.push('_close')
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}
|
||||
|
||||
const order = []
|
||||
const db = mockLevel({
|
||||
_open (options, callback) {
|
||||
order.push('_open')
|
||||
this.nextTick(callback)
|
||||
},
|
||||
[privateMethod] (options) {
|
||||
order.push(privateMethod)
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
})
|
||||
|
||||
const it = db[publicMethod]()
|
||||
t.ok(it instanceof DeferredCtor)
|
||||
|
||||
it.close(function (err) {
|
||||
t.ifError(err, 'no close() error')
|
||||
t.same(order, ['_open', privateMethod, '_close'])
|
||||
})
|
||||
})
|
||||
|
||||
const verifyClosed = function (t, it, method, cb) {
|
||||
const requiredArgs = method === 'nextv' ? [10] : []
|
||||
|
||||
it[method](...requiredArgs, function (err) {
|
||||
t.is(err && err.code, 'LEVEL_ITERATOR_NOT_OPEN', `correct error on first ${method}()`)
|
||||
|
||||
// Should account for userland code that ignores errors
|
||||
it[method](...requiredArgs, function (err) {
|
||||
t.is(err && err.code, 'LEVEL_ITERATOR_NOT_OPEN', `correct error on second ${method}()`)
|
||||
cb()
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
93
node_modules/abstract-level/test/self/deferred-operations-test.js
generated
vendored
Normal file
93
node_modules/abstract-level/test/self/deferred-operations-test.js
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
'use strict'
|
||||
|
||||
const test = require('tape')
|
||||
const { mockLevel, mockIterator } = require('../util')
|
||||
|
||||
// NOTE: copied from deferred-leveldown
|
||||
test('deferred operations are called in order', function (t) {
|
||||
t.plan(15)
|
||||
|
||||
const calls = []
|
||||
const db = mockLevel({
|
||||
_put: function (key, value, options, callback) {
|
||||
this.nextTick(callback)
|
||||
calls.push({ type: 'put', key, value, options })
|
||||
},
|
||||
_get: function (key, options, callback) {
|
||||
this.nextTick(callback)
|
||||
calls.push({ type: 'get', key, options })
|
||||
},
|
||||
_del: function (key, options, callback) {
|
||||
this.nextTick(callback)
|
||||
calls.push({ type: 'del', key, options })
|
||||
},
|
||||
_batch: function (arr, options, callback) {
|
||||
this.nextTick(callback)
|
||||
calls.push({ type: 'batch', keys: arr.map(op => op.key).join(',') })
|
||||
},
|
||||
_clear: function (options, callback) {
|
||||
this.nextTick(callback)
|
||||
calls.push({ ...options, type: 'clear' })
|
||||
},
|
||||
_iterator (options) {
|
||||
calls.push({ type: 'iterator' })
|
||||
return mockIterator(this, options, {
|
||||
_next (callback) {
|
||||
this.nextTick(callback)
|
||||
calls.push({ type: 'iterator.next' })
|
||||
}
|
||||
})
|
||||
},
|
||||
_open: function (options, callback) {
|
||||
this.nextTick(callback)
|
||||
t.is(calls.length, 0, 'not yet called')
|
||||
}
|
||||
}, {
|
||||
encodings: {
|
||||
utf8: true,
|
||||
buffer: true
|
||||
}
|
||||
}, {
|
||||
keyEncoding: 'utf8',
|
||||
valueEncoding: 'utf8'
|
||||
})
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open() error')
|
||||
t.same(calls, [
|
||||
{ type: 'put', key: '001', value: 'bar1', options: { keyEncoding: 'utf8', valueEncoding: 'utf8' } },
|
||||
{ type: 'get', key: '002', options: { keyEncoding: 'utf8', valueEncoding: 'utf8' } },
|
||||
{ type: 'clear', reverse: false, limit: -1, keyEncoding: 'utf8' },
|
||||
{ type: 'put', key: '010', value: 'bar2', options: { keyEncoding: 'utf8', valueEncoding: 'utf8' } },
|
||||
{ type: 'get', key: Buffer.from('011'), options: { keyEncoding: 'buffer', valueEncoding: 'utf8' } },
|
||||
{ type: 'del', key: '020', options: { customOption: 123, keyEncoding: 'utf8' } },
|
||||
{ type: 'del', key: '021', options: { keyEncoding: 'utf8' } },
|
||||
{ type: 'batch', keys: '040,041' },
|
||||
{ type: 'iterator' },
|
||||
{ type: 'batch', keys: '050,051' },
|
||||
{ type: 'iterator.next' },
|
||||
{ type: 'clear', gt: '060', reverse: false, limit: -1, keyEncoding: 'utf8' }
|
||||
], 'calls correctly behaved')
|
||||
})
|
||||
|
||||
db.put('001', 'bar1', t.ifError.bind(t))
|
||||
db.get('002', t.ifError.bind(t))
|
||||
db.clear(t.ifError.bind(t))
|
||||
db.put('010', 'bar2', t.ifError.bind(t))
|
||||
db.get('011', { keyEncoding: 'buffer' }, t.ifError.bind(t))
|
||||
db.del('020', { customOption: 123 }, t.ifError.bind(t))
|
||||
db.del('021', t.ifError.bind(t))
|
||||
db.batch([
|
||||
{ type: 'put', key: '040', value: 'a' },
|
||||
{ type: 'put', key: '041', value: 'b' }
|
||||
], t.ifError.bind(t))
|
||||
const it = db.iterator()
|
||||
db.batch()
|
||||
.put('050', 'c')
|
||||
.put('051', 'd')
|
||||
.write(t.ifError.bind(t))
|
||||
it.next(t.ifError.bind(t))
|
||||
db.clear({ gt: '060' }, t.ifError.bind(t))
|
||||
|
||||
t.is(calls.length, 0, 'not yet called')
|
||||
})
|
426
node_modules/abstract-level/test/self/encoding-test.js
generated
vendored
Normal file
426
node_modules/abstract-level/test/self/encoding-test.js
generated
vendored
Normal file
@ -0,0 +1,426 @@
|
||||
'use strict'
|
||||
|
||||
// TODO: move to per-method test files
|
||||
|
||||
const test = require('tape')
|
||||
const { Buffer } = require('buffer')
|
||||
const { mockLevel, mockChainedBatch, nullishEncoding } = require('../util')
|
||||
const identity = (v) => v
|
||||
|
||||
const utf8Manifest = { encodings: { utf8: true } }
|
||||
const dualManifest = { encodings: { utf8: true, buffer: true } }
|
||||
const hasOwnProperty = Object.prototype.hasOwnProperty
|
||||
|
||||
for (const deferred of [false, true]) {
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`get() encodes utf8 key (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = mockLevel({
|
||||
_get (key, options, callback) {
|
||||
t.is(key, '8')
|
||||
t.is(options.keyEncoding, 'utf8')
|
||||
t.is(options.valueEncoding, 'utf8')
|
||||
this.nextTick(callback, null, 'foo')
|
||||
}
|
||||
}, utf8Manifest)
|
||||
|
||||
if (!deferred) await db.open()
|
||||
t.same(await db.get(8), 'foo')
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`get() takes encoding options (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = mockLevel({
|
||||
_get (key, options, callback) {
|
||||
t.is(key, '[1,"2"]')
|
||||
t.is(options.keyEncoding, 'utf8')
|
||||
t.is(options.valueEncoding, 'utf8')
|
||||
this.nextTick(callback, null, '123')
|
||||
}
|
||||
}, utf8Manifest)
|
||||
|
||||
if (!deferred) await db.open()
|
||||
t.same(await db.get([1, '2'], { keyEncoding: 'json', valueEncoding: 'json' }), 123)
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`get() with custom value encoding that wants a buffer (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(3)
|
||||
|
||||
const db = mockLevel({
|
||||
_get (key, options, callback) {
|
||||
t.same(key, 'key')
|
||||
t.same(options, { keyEncoding: 'utf8', valueEncoding: 'buffer' })
|
||||
this.nextTick(callback, null, Buffer.alloc(1))
|
||||
}
|
||||
}, dualManifest, {
|
||||
keyEncoding: 'utf8',
|
||||
valueEncoding: { encode: identity, decode: identity, format: 'buffer' }
|
||||
})
|
||||
|
||||
if (!deferred) await db.open()
|
||||
t.same(await db.get('key'), Buffer.alloc(1))
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`get() with custom value encoding that wants a string (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(3)
|
||||
|
||||
const db = mockLevel({
|
||||
_get (key, options, callback) {
|
||||
t.same(key, Buffer.from('key'))
|
||||
t.same(options, { keyEncoding: 'buffer', valueEncoding: 'utf8' })
|
||||
this.nextTick(callback, null, 'x')
|
||||
}
|
||||
}, dualManifest, {
|
||||
keyEncoding: 'buffer',
|
||||
valueEncoding: { encode: identity, decode: identity, format: 'utf8' }
|
||||
})
|
||||
|
||||
if (!deferred) await db.open()
|
||||
t.same(await db.get(Buffer.from('key')), 'x')
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`put() encodes utf8 key and value (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = mockLevel({
|
||||
_put (key, value, options, callback) {
|
||||
t.is(key, '8')
|
||||
t.is(value, '4')
|
||||
t.is(options.keyEncoding, 'utf8')
|
||||
t.is(options.valueEncoding, 'utf8')
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}, utf8Manifest)
|
||||
|
||||
if (!deferred) await db.open()
|
||||
await db.put(8, 4)
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`put() takes encoding options (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = mockLevel({
|
||||
_put (key, value, options, callback) {
|
||||
t.is(key, '[1,"2"]')
|
||||
t.is(value, '{"x":3}')
|
||||
t.is(options.keyEncoding, 'utf8')
|
||||
t.is(options.valueEncoding, 'utf8')
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}, utf8Manifest)
|
||||
|
||||
if (!deferred) await db.open()
|
||||
await db.put([1, '2'], { x: 3 }, { keyEncoding: 'json', valueEncoding: 'json' })
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`del() encodes utf8 key (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
const db = mockLevel({
|
||||
_del (key, options, callback) {
|
||||
t.is(key, '2')
|
||||
t.is(options.keyEncoding, 'utf8')
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}, utf8Manifest)
|
||||
|
||||
if (!deferred) await db.open()
|
||||
await db.del(2)
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`del() takes keyEncoding option (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
const db = mockLevel({
|
||||
_del (key, options, callback) {
|
||||
t.is(key, '[1,"2"]')
|
||||
t.is(options.keyEncoding, 'utf8')
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}, utf8Manifest)
|
||||
|
||||
if (!deferred) await db.open()
|
||||
await db.del([1, '2'], { keyEncoding: 'json' })
|
||||
})
|
||||
|
||||
test(`getMany() encodes utf8 key (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = mockLevel({
|
||||
_getMany (keys, options, callback) {
|
||||
t.same(keys, ['8', '29'])
|
||||
t.is(options.keyEncoding, 'utf8')
|
||||
t.is(options.valueEncoding, 'utf8')
|
||||
this.nextTick(callback, null, ['foo', 'bar'])
|
||||
}
|
||||
}, utf8Manifest)
|
||||
|
||||
if (!deferred) await db.open()
|
||||
t.same(await db.getMany([8, 29]), ['foo', 'bar'])
|
||||
})
|
||||
|
||||
test(`getMany() takes encoding options (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = mockLevel({
|
||||
_getMany (keys, options, callback) {
|
||||
t.same(keys, ['[1,"2"]', '"x"'])
|
||||
t.is(options.keyEncoding, 'utf8')
|
||||
t.is(options.valueEncoding, 'utf8')
|
||||
this.nextTick(callback, null, ['123', '"hi"'])
|
||||
}
|
||||
}, utf8Manifest)
|
||||
|
||||
if (!deferred) await db.open()
|
||||
t.same(await db.getMany([[1, '2'], 'x'], { keyEncoding: 'json', valueEncoding: 'json' }), [123, 'hi'])
|
||||
})
|
||||
|
||||
test(`getMany() with custom value encoding that wants a buffer (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(3)
|
||||
|
||||
const db = mockLevel({
|
||||
_getMany (keys, options, callback) {
|
||||
t.same(keys, ['key'])
|
||||
t.same(options, { keyEncoding: 'utf8', valueEncoding: 'buffer' })
|
||||
this.nextTick(callback, null, [Buffer.alloc(1)])
|
||||
}
|
||||
}, dualManifest, {
|
||||
keyEncoding: 'utf8',
|
||||
valueEncoding: { encode: identity, decode: identity, format: 'buffer' }
|
||||
})
|
||||
|
||||
if (!deferred) await db.open()
|
||||
t.same(await db.getMany(['key']), [Buffer.alloc(1)])
|
||||
})
|
||||
|
||||
test(`getMany() with custom value encoding that wants a string (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(3)
|
||||
|
||||
const db = mockLevel({
|
||||
_getMany (keys, options, callback) {
|
||||
t.same(keys, [Buffer.from('key')])
|
||||
t.same(options, { keyEncoding: 'buffer', valueEncoding: 'utf8' })
|
||||
this.nextTick(callback, null, ['x'])
|
||||
}
|
||||
}, dualManifest, {
|
||||
keyEncoding: 'buffer',
|
||||
valueEncoding: { encode: identity, decode: identity, format: 'utf8' }
|
||||
})
|
||||
|
||||
if (!deferred) await db.open()
|
||||
t.same(await db.getMany([Buffer.from('key')]), ['x'])
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`chainedBatch.put() and del() encode utf8 key and value (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(deferred ? 2 : 4)
|
||||
|
||||
let db
|
||||
|
||||
if (deferred) {
|
||||
db = mockLevel({
|
||||
_batch (array, options, callback) {
|
||||
t.same(array, [
|
||||
{ type: 'put', key: '1', value: '2', keyEncoding: 'utf8', valueEncoding: 'utf8' },
|
||||
{ type: 'del', key: '3', keyEncoding: 'utf8' }
|
||||
])
|
||||
t.same(options, {})
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}, utf8Manifest)
|
||||
} else {
|
||||
db = mockLevel({
|
||||
_chainedBatch () {
|
||||
return mockChainedBatch(this, {
|
||||
_put: function (key, value, options) {
|
||||
t.same({ key, value }, { key: '1', value: '2' })
|
||||
t.same(options, { keyEncoding: 'utf8', valueEncoding: 'utf8' })
|
||||
},
|
||||
_del: function (key, options) {
|
||||
t.is(key, '3')
|
||||
t.same(options, { keyEncoding: 'utf8' })
|
||||
}
|
||||
})
|
||||
}
|
||||
}, utf8Manifest)
|
||||
}
|
||||
|
||||
if (!deferred) await db.open()
|
||||
await db.batch().put(1, 2).del(3).write()
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`chainedBatch.put() and del() take encoding options (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(deferred ? 2 : 4)
|
||||
|
||||
let db
|
||||
|
||||
const putOptions = { keyEncoding: 'json', valueEncoding: 'json' }
|
||||
const delOptions = { keyEncoding: 'json' }
|
||||
|
||||
if (deferred) {
|
||||
db = mockLevel({
|
||||
_batch (array, options, callback) {
|
||||
t.same(array, [
|
||||
{ type: 'put', key: '"1"', value: '{"x":[2]}', keyEncoding: 'utf8', valueEncoding: 'utf8' },
|
||||
{ type: 'del', key: '"3"', keyEncoding: 'utf8' }
|
||||
])
|
||||
t.same(options, {})
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}, utf8Manifest)
|
||||
} else {
|
||||
db = mockLevel({
|
||||
_chainedBatch () {
|
||||
return mockChainedBatch(this, {
|
||||
_put: function (key, value, options) {
|
||||
t.same({ key, value }, { key: '"1"', value: '{"x":[2]}' })
|
||||
t.same(options, { keyEncoding: 'utf8', valueEncoding: 'utf8' })
|
||||
},
|
||||
_del: function (key, options) {
|
||||
t.is(key, '"3"')
|
||||
t.same(options, { keyEncoding: 'utf8' })
|
||||
}
|
||||
})
|
||||
}
|
||||
}, utf8Manifest)
|
||||
}
|
||||
|
||||
if (!deferred) await db.open()
|
||||
await db.batch().put('1', { x: [2] }, putOptions).del('3', delOptions).write()
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`clear() receives keyEncoding option (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(1)
|
||||
|
||||
const db = mockLevel({
|
||||
_clear: function (options, callback) {
|
||||
t.same(options, { keyEncoding: 'utf8', reverse: false, limit: -1 })
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}, utf8Manifest)
|
||||
|
||||
if (!deferred) await db.open()
|
||||
await db.clear()
|
||||
})
|
||||
|
||||
test(`clear() takes keyEncoding option (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(1)
|
||||
|
||||
const db = mockLevel({
|
||||
_clear: function (options, callback) {
|
||||
t.same(options, { keyEncoding: 'utf8', gt: '"a"', reverse: false, limit: -1 })
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}, utf8Manifest)
|
||||
|
||||
if (!deferred) await db.open()
|
||||
await db.clear({ keyEncoding: 'json', gt: 'a' })
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`clear() encodes range options (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(5)
|
||||
|
||||
const keyEncoding = {
|
||||
format: 'utf8',
|
||||
encode: function (key) {
|
||||
return 'encoded_' + key
|
||||
},
|
||||
decode: identity
|
||||
}
|
||||
|
||||
const db = mockLevel({
|
||||
_clear: function (options, callback) {
|
||||
t.is(options.gt, 'encoded_1')
|
||||
t.is(options.gte, 'encoded_2')
|
||||
t.is(options.lt, 'encoded_3')
|
||||
t.is(options.lte, 'encoded_4')
|
||||
t.is(options.foo, 5)
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}, utf8Manifest, { keyEncoding })
|
||||
|
||||
if (!deferred) await db.open()
|
||||
await db.clear({ gt: 1, gte: 2, lt: 3, lte: 4, foo: 5 })
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`clear() does not strip nullish range options (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(12)
|
||||
|
||||
const db1 = mockLevel({
|
||||
_clear: function (options, callback) {
|
||||
t.is(options.gt, '\x00', 'encoded null')
|
||||
t.is(options.gte, '\x00', 'encoded null')
|
||||
t.is(options.lt, '\x00', 'encoded null')
|
||||
t.is(options.lte, '\x00', 'encoded null')
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}, utf8Manifest, { keyEncoding: nullishEncoding, valueEncoding: nullishEncoding })
|
||||
|
||||
const db2 = mockLevel({
|
||||
_clear: function (options, callback) {
|
||||
t.is(hasOwnProperty.call(options, 'gt'), true)
|
||||
t.is(hasOwnProperty.call(options, 'gte'), true)
|
||||
t.is(hasOwnProperty.call(options, 'lt'), true)
|
||||
t.is(hasOwnProperty.call(options, 'lte'), true)
|
||||
|
||||
t.is(options.gt, '\xff', 'encoded undefined')
|
||||
t.is(options.gte, '\xff', 'encoded undefined')
|
||||
t.is(options.lt, '\xff', 'encoded undefined')
|
||||
t.is(options.lte, '\xff', 'encoded undefined')
|
||||
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}, utf8Manifest, { keyEncoding: nullishEncoding, valueEncoding: nullishEncoding })
|
||||
|
||||
if (!deferred) {
|
||||
await Promise.all([db1.open(), db2.open()])
|
||||
}
|
||||
|
||||
const promise1 = db1.clear({
|
||||
gt: null,
|
||||
gte: null,
|
||||
lt: null,
|
||||
lte: null
|
||||
})
|
||||
|
||||
const promise2 = db2.clear({
|
||||
gt: undefined,
|
||||
gte: undefined,
|
||||
lt: undefined,
|
||||
lte: undefined
|
||||
})
|
||||
|
||||
await Promise.all([promise1, promise2])
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`clear() does not add nullish range options (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = mockLevel({
|
||||
_clear: function (options, callback) {
|
||||
t.is(hasOwnProperty.call(options, 'gt'), false)
|
||||
t.is(hasOwnProperty.call(options, 'gte'), false)
|
||||
t.is(hasOwnProperty.call(options, 'lt'), false)
|
||||
t.is(hasOwnProperty.call(options, 'lte'), false)
|
||||
this.nextTick(callback)
|
||||
}
|
||||
})
|
||||
|
||||
if (!deferred) await db.open()
|
||||
await db.clear({})
|
||||
})
|
||||
}
|
829
node_modules/abstract-level/test/self/iterator-test.js
generated
vendored
Normal file
829
node_modules/abstract-level/test/self/iterator-test.js
generated
vendored
Normal file
@ -0,0 +1,829 @@
|
||||
'use strict'
|
||||
|
||||
const test = require('tape')
|
||||
const { Buffer } = require('buffer')
|
||||
const { AbstractLevel } = require('../..')
|
||||
const { AbstractIterator, AbstractKeyIterator, AbstractValueIterator } = require('../..')
|
||||
const { mockLevel, mockIterator, nullishEncoding } = require('../util')
|
||||
|
||||
const identity = (v) => v
|
||||
const utf8Manifest = { encodings: { utf8: true } }
|
||||
const dualManifest = { encodings: { utf8: true, buffer: true } }
|
||||
const tripleManifest = { encodings: { utf8: true, buffer: true, view: true } }
|
||||
|
||||
for (const deferred of [false, true]) {
|
||||
// Also test default fallback implementations of keys() and values()
|
||||
for (const [mode, def] of [['iterator', false], ['keys', false], ['values', false], ['keys', true], ['values', true]]) {
|
||||
const Ctor = mode === 'iterator' || def ? AbstractIterator : mode === 'keys' ? AbstractKeyIterator : AbstractValueIterator
|
||||
const privateMethod = def ? '_iterator' : '_' + mode
|
||||
const publicMethod = mode
|
||||
|
||||
test(`${mode}() (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
let called = false
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
t.is(this, db, 'thisArg is correct')
|
||||
t.is(arguments.length, 1, 'got one argument')
|
||||
|
||||
const kvOptions = mode === 'iterator' || def
|
||||
? { keys: mode !== 'values', values: mode !== 'keys' }
|
||||
: {}
|
||||
|
||||
t.same(options, {
|
||||
reverse: false,
|
||||
limit: -1,
|
||||
keyEncoding: 'utf8',
|
||||
valueEncoding: 'utf8',
|
||||
...kvOptions
|
||||
})
|
||||
|
||||
called = true
|
||||
return new Ctor(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(tripleManifest)
|
||||
if (!deferred) await db.open()
|
||||
|
||||
db[publicMethod]()
|
||||
t.is(called, !deferred)
|
||||
if (deferred) await db.open()
|
||||
})
|
||||
|
||||
test(`${mode}() with custom options (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(3)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
t.is(options.foo, 123)
|
||||
t.is(options.reverse, true)
|
||||
t.is(options.limit, 1)
|
||||
|
||||
return new Ctor(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(tripleManifest)
|
||||
if (!deferred) await db.open()
|
||||
db[publicMethod]({ foo: 123, reverse: true, limit: 1 })
|
||||
if (deferred) await db.open()
|
||||
})
|
||||
|
||||
for (const limit of [2, 0]) {
|
||||
test(`${mode}().next() skips _next() when limit ${limit} is reached (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
let calls = 0
|
||||
let yielded = 0
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_next (callback) {
|
||||
calls++
|
||||
|
||||
if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, 'a', 'a')
|
||||
} else {
|
||||
this.nextTick(callback, null, 'a')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(utf8Manifest)
|
||||
if (!deferred) await db.open()
|
||||
|
||||
const it = db[publicMethod]({ limit })
|
||||
|
||||
for (let i = 0; i < limit + 2; i++) {
|
||||
const item = await it.next()
|
||||
if (item === undefined) break
|
||||
yielded++
|
||||
}
|
||||
|
||||
t.is(it.count, limit, 'final count matches limit')
|
||||
t.is(calls, limit)
|
||||
t.is(yielded, limit)
|
||||
})
|
||||
|
||||
test(`${mode}().nextv() skips _nextv() when limit ${limit} is reached (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
let calls = 0
|
||||
let yielded = 0
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_nextv (size, options, callback) {
|
||||
calls++
|
||||
|
||||
if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, [['a', 'a']])
|
||||
} else {
|
||||
this.nextTick(callback, null, ['a'])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(utf8Manifest)
|
||||
if (!deferred) await db.open()
|
||||
|
||||
const it = db[publicMethod]({ limit })
|
||||
|
||||
for (let i = 0; i < limit + 2; i++) {
|
||||
const items = await it.nextv(1)
|
||||
yielded += items.length
|
||||
if (items.length === 0) break
|
||||
}
|
||||
|
||||
t.is(it.count, limit, 'final count matches limit')
|
||||
t.is(calls, limit)
|
||||
t.is(yielded, limit)
|
||||
})
|
||||
|
||||
test(`${mode}().all() skips _all() when limit ${limit} is reached (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
let nextCount = 0
|
||||
class MockIterator extends Ctor {
|
||||
_next (callback) {
|
||||
if (++nextCount > 10) {
|
||||
throw new Error('Potential infinite loop')
|
||||
} else if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, 'a', 'a')
|
||||
} else {
|
||||
this.nextTick(callback, null, 'a')
|
||||
}
|
||||
}
|
||||
|
||||
_all (options, callback) {
|
||||
t.fail('should not be called')
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(utf8Manifest)
|
||||
if (!deferred) await db.open()
|
||||
|
||||
const it = db[publicMethod]({ limit })
|
||||
|
||||
// Use next() because all() auto-closes and thus can't be used twice atm
|
||||
for (let i = 0; i < limit; i++) await it.next()
|
||||
|
||||
t.same(await it.all(), [])
|
||||
})
|
||||
}
|
||||
|
||||
test(`${mode}().nextv() reduces size for _nextv() when near limit (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_nextv (size, options, callback) {
|
||||
if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, Array(size).fill(['a', 'a']))
|
||||
} else {
|
||||
this.nextTick(callback, null, Array(size).fill('a'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(utf8Manifest)
|
||||
if (!deferred) await db.open()
|
||||
|
||||
const it = db[publicMethod]({ limit: 3 })
|
||||
|
||||
t.is((await it.nextv(2)).length, 2)
|
||||
t.is((await it.nextv(2)).length, 1)
|
||||
t.is((await it.nextv(2)).length, 0)
|
||||
})
|
||||
|
||||
test(`${mode}().count increments by next(), nextv() and all() (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_next (callback) {
|
||||
if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, 'a', 'a')
|
||||
} else {
|
||||
this.nextTick(callback, null, 'a')
|
||||
}
|
||||
}
|
||||
|
||||
_nextv (size, options, callback) {
|
||||
if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, [['a', 'a'], ['b', 'b']])
|
||||
} else {
|
||||
this.nextTick(callback, null, ['a', 'b'])
|
||||
}
|
||||
}
|
||||
|
||||
_all (options, callback) {
|
||||
if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, [['c', 'c'], ['d', 'd'], ['e', 'e']])
|
||||
} else {
|
||||
this.nextTick(callback, null, ['c', 'd', 'e'])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(utf8Manifest)
|
||||
if (!deferred) await db.open()
|
||||
|
||||
const it = db[publicMethod]()
|
||||
|
||||
for (let i = 0; i < 2; i++) {
|
||||
t.isNot(await it.next(), undefined) // 2 * 1 = 2
|
||||
t.is((await it.nextv(2)).length, 2) // 2 * 2 = 4
|
||||
}
|
||||
|
||||
t.is(it.count, 2 + 4)
|
||||
t.is((await it.all()).length, 3)
|
||||
t.is(it.count, 2 + 4 + 3)
|
||||
})
|
||||
|
||||
test(`${mode}() forwards encoding options (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(3)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
t.is(options.keyEncoding, 'utf8')
|
||||
t.is(options.valueEncoding, 'buffer')
|
||||
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_next (callback) {
|
||||
if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, '281', Buffer.from('a'))
|
||||
} else if (mode === 'keys') {
|
||||
this.nextTick(callback, null, '281')
|
||||
} else {
|
||||
this.nextTick(callback, null, Buffer.from('a'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(dualManifest)
|
||||
if (!deferred) await db.open()
|
||||
|
||||
const item = await db[publicMethod]({ keyEncoding: 'json', valueEncoding: 'hex' }).next()
|
||||
t.same(item, mode === 'iterator' ? [281, '61'] : mode === 'keys' ? 281 : '61')
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`${mode}() with custom encodings that want a buffer (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(5)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
t.is(options.keyEncoding, 'buffer')
|
||||
t.is(options.valueEncoding, 'buffer')
|
||||
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_next (callback) {
|
||||
if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, Buffer.from('a'), Buffer.from('b'))
|
||||
} else if (mode === 'keys') {
|
||||
this.nextTick(callback, null, Buffer.from('a'))
|
||||
} else {
|
||||
this.nextTick(callback, null, Buffer.from('b'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(dualManifest)
|
||||
const encoding = { encode: spy(identity), decode: spy(identity), format: 'buffer' }
|
||||
if (!deferred) await db.open()
|
||||
|
||||
const it = db[publicMethod]({ keyEncoding: encoding, valueEncoding: encoding })
|
||||
const item = await it.next()
|
||||
|
||||
t.is(encoding.encode.calls, 0, 'did not need to encode anything')
|
||||
t.is(encoding.decode.calls, mode === 'iterator' ? 2 : 1)
|
||||
t.same(item, mode === 'iterator' ? [Buffer.from('a'), Buffer.from('b')] : Buffer.from(mode === 'keys' ? 'a' : 'b'))
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`${mode}() with custom encodings that want a string (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(5)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
t.is(options.keyEncoding, 'utf8')
|
||||
t.is(options.valueEncoding, 'utf8')
|
||||
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_next (callback) {
|
||||
if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, 'a', 'b')
|
||||
} else if (mode === 'keys') {
|
||||
this.nextTick(callback, null, 'a')
|
||||
} else {
|
||||
this.nextTick(callback, null, 'b')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(dualManifest)
|
||||
const encoding = { encode: spy(identity), decode: spy(identity), format: 'utf8' }
|
||||
if (!deferred) await db.open()
|
||||
|
||||
const it = db[publicMethod]({ keyEncoding: encoding, valueEncoding: encoding })
|
||||
const item = await it.next()
|
||||
|
||||
t.is(encoding.encode.calls, 0, 'did not need to encode anything')
|
||||
t.is(encoding.decode.calls, mode === 'iterator' ? 2 : 1)
|
||||
t.same(item, mode === 'iterator' ? ['a', 'b'] : mode === 'keys' ? 'a' : 'b')
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`${mode}() encodes range options (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(6)
|
||||
|
||||
let calls = 0
|
||||
const keyEncoding = {
|
||||
format: 'utf8',
|
||||
encode (key) {
|
||||
calls++
|
||||
return 'encoded_' + key
|
||||
},
|
||||
decode: identity
|
||||
}
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
t.is(options.gt, 'encoded_3')
|
||||
t.is(options.gte, 'encoded_4')
|
||||
t.is(options.lt, 'encoded_5')
|
||||
t.is(options.lte, 'encoded_6')
|
||||
t.is(options.foo, 7)
|
||||
return new Ctor(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(utf8Manifest, { keyEncoding })
|
||||
if (!deferred) await db.open()
|
||||
await db[publicMethod]({ gt: 3, gte: 4, lt: 5, lte: 6, foo: 7 }).next()
|
||||
t.is(calls, 4)
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`${mode}() does not strip nullish range options (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(12)
|
||||
|
||||
const db1 = mockLevel({
|
||||
[privateMethod] (options) {
|
||||
t.is(options.gt, '\x00', 'encoded null')
|
||||
t.is(options.gte, '\x00', 'encoded null')
|
||||
t.is(options.lt, '\x00', 'encoded null')
|
||||
t.is(options.lte, '\x00', 'encoded null')
|
||||
|
||||
return new Ctor(this, options)
|
||||
}
|
||||
}, utf8Manifest, { keyEncoding: nullishEncoding, valueEncoding: nullishEncoding })
|
||||
|
||||
const db2 = mockLevel({
|
||||
[privateMethod] (options) {
|
||||
t.is(hasOwnProperty.call(options, 'gt'), true)
|
||||
t.is(hasOwnProperty.call(options, 'gte'), true)
|
||||
t.is(hasOwnProperty.call(options, 'lt'), true)
|
||||
t.is(hasOwnProperty.call(options, 'lte'), true)
|
||||
|
||||
t.is(options.gt, '\xff', 'encoded undefined')
|
||||
t.is(options.gte, '\xff', 'encoded undefined')
|
||||
t.is(options.lt, '\xff', 'encoded undefined')
|
||||
t.is(options.lte, '\xff', 'encoded undefined')
|
||||
|
||||
return new Ctor(this, options)
|
||||
}
|
||||
}, utf8Manifest, { keyEncoding: nullishEncoding, valueEncoding: nullishEncoding })
|
||||
|
||||
if (!deferred) {
|
||||
await Promise.all([db1.open(), db2.open()])
|
||||
}
|
||||
|
||||
const promise1 = db1[publicMethod]({
|
||||
gt: null,
|
||||
gte: null,
|
||||
lt: null,
|
||||
lte: null
|
||||
}).next()
|
||||
|
||||
const promise2 = db2[publicMethod]({
|
||||
gt: undefined,
|
||||
gte: undefined,
|
||||
lt: undefined,
|
||||
lte: undefined
|
||||
}).next()
|
||||
|
||||
return Promise.all([promise1, promise2])
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`${mode}() does not add nullish range options (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = mockLevel({
|
||||
[privateMethod] (options) {
|
||||
t.is(hasOwnProperty.call(options, 'gt'), false)
|
||||
t.is(hasOwnProperty.call(options, 'gte'), false)
|
||||
t.is(hasOwnProperty.call(options, 'lt'), false)
|
||||
t.is(hasOwnProperty.call(options, 'lte'), false)
|
||||
|
||||
return new Ctor(this, options)
|
||||
}
|
||||
})
|
||||
|
||||
if (!deferred) await db.open()
|
||||
await db[publicMethod]({}).next()
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`${mode}() encodes seek target (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
const db = mockLevel({
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}, utf8Manifest, { keyEncoding: 'json' })
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_seek (target, options) {
|
||||
t.is(target, '"a"', 'encoded once')
|
||||
t.same(options, { keyEncoding: 'utf8' })
|
||||
}
|
||||
}
|
||||
|
||||
if (!deferred) await db.open()
|
||||
const it = db[publicMethod]()
|
||||
it.seek('a')
|
||||
await it.next()
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`${mode}() encodes seek target with custom encoding (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(1)
|
||||
|
||||
const targets = []
|
||||
const db = mockLevel({
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}, utf8Manifest)
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_seek (target) {
|
||||
targets.push(target)
|
||||
}
|
||||
}
|
||||
|
||||
if (!deferred) await db.open()
|
||||
|
||||
db[publicMethod]().seek('a')
|
||||
db[publicMethod]({ keyEncoding: 'json' }).seek('a')
|
||||
db[publicMethod]().seek('b', { keyEncoding: 'json' })
|
||||
|
||||
await db.open()
|
||||
t.same(targets, ['a', '"a"', '"b"'], 'encoded targets')
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`${mode}() encodes nullish seek target (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(1)
|
||||
|
||||
const targets = []
|
||||
const db = mockLevel({
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}, utf8Manifest, { keyEncoding: { encode: String, decode: identity, format: 'utf8' } })
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_seek (target) {
|
||||
targets.push(target)
|
||||
}
|
||||
}
|
||||
|
||||
if (!deferred) await db.open()
|
||||
|
||||
// Unlike keys, nullish targets should not be rejected;
|
||||
// assume that the encoding gives these types meaning.
|
||||
db[publicMethod]().seek(null)
|
||||
db[publicMethod]().seek(undefined)
|
||||
|
||||
await db.open()
|
||||
t.same(targets, ['null', 'undefined'], 'encoded')
|
||||
})
|
||||
|
||||
test(`${mode}() has default nextv() (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
const sizes = [[1, [0]], [1, [1]], [2, [2]], [3, [3]]]
|
||||
t.plan(sizes.length * 2)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
let pos = 0
|
||||
class MockIterator extends Ctor {
|
||||
_next (callback) {
|
||||
if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, 'k' + pos, 'v' + (pos++))
|
||||
} else if (mode === 'keys') {
|
||||
this.nextTick(callback, null, 'k' + (pos++))
|
||||
} else {
|
||||
this.nextTick(callback, null, 'v' + (pos++))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(utf8Manifest)
|
||||
if (!deferred) await db.open()
|
||||
|
||||
let expectedPos = 0
|
||||
const it = db[publicMethod]()
|
||||
|
||||
for (const [size, args] of sizes) {
|
||||
const actual = await it.nextv(...args)
|
||||
const expected = []
|
||||
|
||||
for (let i = 0; i < size; i++) {
|
||||
const pos = expectedPos++
|
||||
if (mode === 'iterator') expected.push(['k' + pos, 'v' + pos])
|
||||
else if (mode === 'keys') expected.push('k' + pos)
|
||||
else expected.push('v' + pos)
|
||||
}
|
||||
|
||||
t.is(actual.length, size)
|
||||
t.same(actual, expected)
|
||||
}
|
||||
})
|
||||
|
||||
test(`${mode}() default nextv() forwards next() error (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_next (callback) {
|
||||
t.pass('called')
|
||||
this.nextTick(callback, new Error('test'))
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(utf8Manifest)
|
||||
if (!deferred) await db.open()
|
||||
|
||||
try {
|
||||
await db[publicMethod]().nextv(10)
|
||||
} catch (err) {
|
||||
t.is(err.message, 'test')
|
||||
}
|
||||
})
|
||||
|
||||
test(`${mode}() has default all() (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(8)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
let pos = 0
|
||||
class MockIterator extends Ctor {
|
||||
_nextv (size, options, callback) {
|
||||
t.is(size, 1000)
|
||||
t.same(options, {})
|
||||
|
||||
if (pos === 4) {
|
||||
this.nextTick(callback, null, [])
|
||||
} else if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, [[String(pos++), 'a'], [String(pos++), 'b']])
|
||||
} else if (mode === 'keys') {
|
||||
this.nextTick(callback, null, [String(pos++), String(pos++)])
|
||||
} else {
|
||||
pos += 2
|
||||
this.nextTick(callback, null, ['a', 'b'])
|
||||
}
|
||||
}
|
||||
|
||||
_close (callback) {
|
||||
t.pass('closed')
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(utf8Manifest)
|
||||
if (!deferred) await db.open()
|
||||
|
||||
t.same(await db[publicMethod]().all(), [
|
||||
['0', 'a'],
|
||||
['1', 'b'],
|
||||
['2', 'a'],
|
||||
['3', 'b']
|
||||
].map(kv => mode === 'iterator' ? kv : kv[mode === 'keys' ? 0 : 1]))
|
||||
})
|
||||
|
||||
test(`${mode}() default all() forwards nextv() error (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_nextv (size, options, callback) {
|
||||
t.pass('called')
|
||||
this.nextTick(callback, new Error('test'))
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(utf8Manifest)
|
||||
if (!deferred) await db.open()
|
||||
|
||||
try {
|
||||
await db[publicMethod]().all()
|
||||
} catch (err) {
|
||||
t.is(err.message, 'test')
|
||||
}
|
||||
})
|
||||
|
||||
test(`${mode}() custom all() (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(3)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_all (options, callback) {
|
||||
t.same(options, {})
|
||||
|
||||
if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, [['k0', 'v0'], ['k1', 'v1']])
|
||||
} else if (mode === 'keys') {
|
||||
this.nextTick(callback, null, ['k0', 'k1'])
|
||||
} else {
|
||||
this.nextTick(callback, null, ['v0', 'v1'])
|
||||
}
|
||||
}
|
||||
|
||||
_close (callback) {
|
||||
t.pass('closed')
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(utf8Manifest)
|
||||
if (!deferred) await db.open()
|
||||
|
||||
t.same(await db[publicMethod]().all(), [
|
||||
['k0', 'v0'],
|
||||
['k1', 'v1']
|
||||
].map(kv => mode === 'iterator' ? kv : kv[mode === 'keys' ? 0 : 1]))
|
||||
})
|
||||
|
||||
test(`${mode}() custom all() forwards error and closes (deferred: ${deferred}, default implementation: ${def})`, async function (t) {
|
||||
t.plan(3)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_all (options, callback) {
|
||||
t.pass('_all called')
|
||||
this.nextTick(callback, new Error('test'))
|
||||
}
|
||||
|
||||
_close (callback) {
|
||||
t.pass('closed')
|
||||
this.nextTick(callback)
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel(utf8Manifest)
|
||||
if (!deferred) await db.open()
|
||||
|
||||
try {
|
||||
await db[publicMethod]().all()
|
||||
} catch (err) {
|
||||
t.is(err.message, 'test')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for (const deferred of [false, true]) {
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`iterator() skips decoding keys if options.keys is false (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(3)
|
||||
|
||||
const keyEncoding = {
|
||||
format: 'utf8',
|
||||
decode (key) {
|
||||
t.fail('should not be called')
|
||||
},
|
||||
encode: identity
|
||||
}
|
||||
|
||||
const db = mockLevel({
|
||||
_iterator (options) {
|
||||
t.is(options.keys, false)
|
||||
|
||||
return mockIterator(this, options, {
|
||||
_next (callback) {
|
||||
this.nextTick(callback, null, '', 'value')
|
||||
}
|
||||
})
|
||||
}
|
||||
}, utf8Manifest, { keyEncoding })
|
||||
|
||||
if (!deferred) await db.open()
|
||||
const [key, value] = await db.iterator({ keys: false }).next()
|
||||
|
||||
t.is(key, undefined, 'normalized key to undefined')
|
||||
t.is(value, 'value', 'got value')
|
||||
})
|
||||
|
||||
// NOTE: adapted from encoding-down
|
||||
test(`iterator() skips decoding values if options.values is false (deferred: ${deferred})`, async function (t) {
|
||||
t.plan(3)
|
||||
|
||||
const valueEncoding = {
|
||||
format: 'utf8',
|
||||
decode (value) {
|
||||
t.fail('should not be called')
|
||||
},
|
||||
encode: identity
|
||||
}
|
||||
|
||||
const db = mockLevel({
|
||||
_iterator (options) {
|
||||
t.is(options.values, false)
|
||||
|
||||
return mockIterator(this, options, {
|
||||
_next (callback) {
|
||||
callback(null, 'key', '')
|
||||
}
|
||||
})
|
||||
}
|
||||
}, utf8Manifest, { valueEncoding })
|
||||
|
||||
if (!deferred) await db.open()
|
||||
const [key, value] = await db.iterator({ values: false }).next()
|
||||
|
||||
t.is(key, 'key', 'got key')
|
||||
t.is(value, undefined, 'normalized value to undefined')
|
||||
})
|
||||
}
|
||||
|
||||
function spy (fn) {
|
||||
const wrapped = function (...args) {
|
||||
wrapped.calls++
|
||||
return fn(...args)
|
||||
}
|
||||
wrapped.calls = 0
|
||||
return wrapped
|
||||
}
|
931
node_modules/abstract-level/test/self/sublevel-test.js
generated
vendored
Normal file
931
node_modules/abstract-level/test/self/sublevel-test.js
generated
vendored
Normal file
@ -0,0 +1,931 @@
|
||||
'use strict'
|
||||
|
||||
const test = require('tape')
|
||||
const { Buffer } = require('buffer')
|
||||
const { AbstractLevel, AbstractSublevel } = require('../..')
|
||||
const { AbstractIterator, AbstractKeyIterator, AbstractValueIterator } = require('../..')
|
||||
const nextTick = AbstractLevel.prototype.nextTick
|
||||
|
||||
class NoopLevel extends AbstractLevel {
|
||||
constructor (...args) {
|
||||
super(
|
||||
{ encodings: { utf8: true, buffer: true, view: true } },
|
||||
...args
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
test('sublevel is extensible', function (t) {
|
||||
t.plan(6)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
_sublevel (name, options) {
|
||||
t.is(name, 'test')
|
||||
t.same(options, { separator: '!', customOption: 123 })
|
||||
|
||||
return new MockSublevel(this, name, {
|
||||
...options,
|
||||
manifest: {
|
||||
encodings: { ignored: true },
|
||||
additionalMethods: { test: true },
|
||||
events: { foo: true }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class MockSublevel extends AbstractSublevel {
|
||||
test () {
|
||||
this.emit('foo')
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel({
|
||||
encodings: { utf8: true },
|
||||
additionalMethods: { ignored: true },
|
||||
events: { ignored: true }
|
||||
})
|
||||
|
||||
const sub = db.sublevel('test', { customOption: 123 })
|
||||
|
||||
t.is(sub.supports.encodings.ignored, undefined)
|
||||
t.same(sub.supports.additionalMethods, { test: true })
|
||||
t.same(sub.supports.events, {
|
||||
foo: true,
|
||||
|
||||
// Added by AbstractLevel
|
||||
opening: true,
|
||||
open: true,
|
||||
closing: true,
|
||||
closed: true,
|
||||
put: true,
|
||||
del: true,
|
||||
batch: true,
|
||||
clear: true
|
||||
})
|
||||
|
||||
sub.on('foo', () => t.pass('emitted'))
|
||||
sub.test()
|
||||
})
|
||||
|
||||
// NOTE: adapted from subleveldown
|
||||
test('sublevel prefix and options', function (t) {
|
||||
t.test('empty prefix', function (t) {
|
||||
const sub = new NoopLevel().sublevel('')
|
||||
t.is(sub.prefix, '!!')
|
||||
t.end()
|
||||
})
|
||||
|
||||
t.test('prefix without options', function (t) {
|
||||
const sub = new NoopLevel().sublevel('prefix')
|
||||
t.is(sub.prefix, '!prefix!')
|
||||
t.end()
|
||||
})
|
||||
|
||||
t.test('prefix and separator option', function (t) {
|
||||
const sub = new NoopLevel().sublevel('prefix', { separator: '%' })
|
||||
t.is(sub.prefix, '%prefix%')
|
||||
t.end()
|
||||
})
|
||||
|
||||
t.test('separator is trimmed from prefix', function (t) {
|
||||
const sub1 = new NoopLevel().sublevel('!prefix')
|
||||
t.is(sub1.prefix, '!prefix!')
|
||||
|
||||
const sub2 = new NoopLevel().sublevel('prefix!')
|
||||
t.is(sub2.prefix, '!prefix!')
|
||||
|
||||
const sub3 = new NoopLevel().sublevel('!!prefix!!')
|
||||
t.is(sub3.prefix, '!prefix!')
|
||||
|
||||
const sub4 = new NoopLevel().sublevel('@prefix@', { separator: '@' })
|
||||
t.is(sub4.prefix, '@prefix@')
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
t.test('repeated separator can not result in empty prefix', function (t) {
|
||||
const sub = new NoopLevel().sublevel('!!!!')
|
||||
t.is(sub.prefix, '!!')
|
||||
t.end()
|
||||
})
|
||||
|
||||
t.test('invalid sublevel prefix', function (t) {
|
||||
t.throws(() => new NoopLevel().sublevel('foo\x05'), (err) => err.code === 'LEVEL_INVALID_PREFIX')
|
||||
t.throws(() => new NoopLevel().sublevel('foo\xff'), (err) => err.code === 'LEVEL_INVALID_PREFIX')
|
||||
t.throws(() => new NoopLevel().sublevel('foo!', { separator: '@' }), (err) => err.code === 'LEVEL_INVALID_PREFIX')
|
||||
t.end()
|
||||
})
|
||||
|
||||
t.test('legacy sublevel(down) options', function (t) {
|
||||
t.throws(() => new NoopLevel().sublevel('foo', 'bar'), (err) => err.code === 'LEVEL_LEGACY')
|
||||
t.throws(() => new NoopLevel().sublevel('foo', { open: () => {} }), (err) => err.code === 'LEVEL_LEGACY')
|
||||
t.end()
|
||||
})
|
||||
|
||||
// See https://github.com/Level/subleveldown/issues/78
|
||||
t.test('doubly nested sublevel has correct prefix', async function (t) {
|
||||
t.plan(1)
|
||||
|
||||
const keys = []
|
||||
class MockLevel extends AbstractLevel {
|
||||
_put (key, value, options, callback) {
|
||||
keys.push(key)
|
||||
nextTick(callback)
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel({ encodings: { utf8: true } })
|
||||
const sub1 = db.sublevel('1')
|
||||
const sub2 = sub1.sublevel('2')
|
||||
const sub3 = sub2.sublevel('3')
|
||||
|
||||
await sub1.put('a', 'value')
|
||||
await sub2.put('b', 'value')
|
||||
await sub3.put('c', 'value')
|
||||
|
||||
t.same(keys.sort(), [
|
||||
'!1!!2!!3!c',
|
||||
'!1!!2!b',
|
||||
'!1!a'
|
||||
])
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('sublevel.prefixKey()', function (t) {
|
||||
const db = new AbstractLevel({ encodings: { utf8: true, buffer: true, view: true } })
|
||||
const sub = db.sublevel('test')
|
||||
const textEncoder = new TextEncoder()
|
||||
|
||||
t.same(sub.prefixKey('', 'utf8'), '!test!')
|
||||
t.same(sub.prefixKey('a', 'utf8'), '!test!a')
|
||||
|
||||
t.same(sub.prefixKey(Buffer.from(''), 'buffer'), Buffer.from('!test!'))
|
||||
t.same(sub.prefixKey(Buffer.from('a'), 'buffer'), Buffer.from('!test!a'))
|
||||
|
||||
t.same(sub.prefixKey(textEncoder.encode(''), 'view'), textEncoder.encode('!test!'))
|
||||
t.same(sub.prefixKey(textEncoder.encode('a'), 'view'), textEncoder.encode('!test!a'))
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
// NOTE: adapted from subleveldown
|
||||
test('sublevel manifest and parent db', function (t) {
|
||||
t.test('sublevel inherits manifest from parent db', function (t) {
|
||||
const parent = new AbstractLevel({
|
||||
encodings: { utf8: true },
|
||||
seek: true,
|
||||
foo: true
|
||||
})
|
||||
const sub = parent.sublevel('')
|
||||
t.is(sub.supports.foo, true, 'AbstractSublevel inherits from parent')
|
||||
t.is(sub.supports.seek, true, 'AbstractSublevel inherits from parent')
|
||||
t.end()
|
||||
})
|
||||
|
||||
t.test('sublevel does not support additionalMethods', function (t) {
|
||||
const parent = new AbstractLevel({
|
||||
encodings: { utf8: true },
|
||||
additionalMethods: { foo: true }
|
||||
})
|
||||
|
||||
// We're expecting that AbstractSublevel removes the additionalMethod
|
||||
// because it can't automatically prefix any key(-like) arguments
|
||||
const sub = parent.sublevel('')
|
||||
t.same(sub.supports.additionalMethods, {})
|
||||
t.same(parent.supports.additionalMethods, { foo: true })
|
||||
t.is(typeof sub.foo, 'undefined', 'AbstractSublevel does not expose method')
|
||||
t.end()
|
||||
})
|
||||
|
||||
t.test('sublevel.db is set to parent db', function (t) {
|
||||
const db = new NoopLevel()
|
||||
const sub = db.sublevel('test')
|
||||
sub.once('open', function () {
|
||||
t.ok(sub.db instanceof NoopLevel)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
// NOTE: adapted from subleveldown
|
||||
test('opening & closing sublevel', function (t) {
|
||||
t.test('error from open() does not bubble up to sublevel', function (t) {
|
||||
t.plan(5)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
_open (opts, cb) {
|
||||
nextTick(cb, new Error('error from underlying store'))
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel({ encodings: { buffer: true } })
|
||||
const sub = db.sublevel('test')
|
||||
|
||||
db.open((err) => {
|
||||
t.is(err && err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
t.is(err && err.cause && err.cause.message, 'error from underlying store')
|
||||
})
|
||||
|
||||
sub.open((err) => {
|
||||
t.is(err && err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
t.is(err && err.cause && err.cause.code, 'LEVEL_DATABASE_NOT_OPEN') // from db
|
||||
t.is(err && err.cause && err.cause.cause, undefined) // but does not have underlying error
|
||||
})
|
||||
})
|
||||
|
||||
t.test('cannot create a sublevel on a closed db', function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const db = new NoopLevel()
|
||||
|
||||
db.once('open', function () {
|
||||
db.close(function (err) {
|
||||
t.error(err, 'no error')
|
||||
|
||||
db.sublevel('test').open(function (err) {
|
||||
t.is(err && err.code, 'LEVEL_DATABASE_NOT_OPEN', 'sublevel not opened')
|
||||
|
||||
db.open(function (err) {
|
||||
t.error(err, 'no error')
|
||||
|
||||
db.sublevel('test').on('open', function () {
|
||||
t.pass('sublevel opened')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.test('can close db and sublevel once opened', function (t) {
|
||||
t.plan(3)
|
||||
|
||||
const db = new NoopLevel()
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open error')
|
||||
const sub = db.sublevel('test')
|
||||
|
||||
sub.once('open', function () {
|
||||
db.close(function (err) {
|
||||
t.ifError(err, 'no close error')
|
||||
})
|
||||
|
||||
sub.close(function (err) {
|
||||
t.ifError(err, 'no close error')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.test('sublevel rejects operations if parent db is closed', function (t) {
|
||||
t.plan(9)
|
||||
|
||||
const db = new NoopLevel()
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open error')
|
||||
|
||||
const sub = db.sublevel('test')
|
||||
const it = sub.iterator()
|
||||
|
||||
sub.once('open', function () {
|
||||
db.close(function (err) {
|
||||
t.ifError(err, 'no close error')
|
||||
|
||||
sub.put('foo', 'bar', verify)
|
||||
sub.get('foo', verify)
|
||||
sub.del('foo', verify)
|
||||
sub.clear(verify)
|
||||
sub.batch([{ type: 'del', key: 'foo' }], verify)
|
||||
|
||||
it.next(function (err) {
|
||||
t.is(err.code, 'LEVEL_ITERATOR_NOT_OPEN')
|
||||
it.close(t.ifError.bind(t))
|
||||
})
|
||||
|
||||
function verify (err) {
|
||||
t.is(err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.test('cannot close db while sublevel is opening', function (t) {
|
||||
t.plan(5)
|
||||
|
||||
const db = new NoopLevel()
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open error')
|
||||
const sub = db.sublevel('test')
|
||||
|
||||
sub.open((err) => {
|
||||
t.is(err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
})
|
||||
|
||||
db.close(function (err) {
|
||||
t.ifError(err, 'no close error')
|
||||
t.is(sub.status, 'closed')
|
||||
t.is(db.status, 'closed')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.test('cannot create sublevel while db is closing', function (t) {
|
||||
t.plan(5)
|
||||
|
||||
const db = new NoopLevel()
|
||||
|
||||
db.open(function (err) {
|
||||
t.ifError(err, 'no open error')
|
||||
|
||||
db.close(function (err) {
|
||||
t.ifError(err, 'no close error')
|
||||
t.is(db.status, 'closed')
|
||||
})
|
||||
|
||||
const sub = db.sublevel('test')
|
||||
|
||||
sub.open((err) => {
|
||||
t.is(err.code, 'LEVEL_DATABASE_NOT_OPEN')
|
||||
t.is(sub.status, 'closed')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.test('can wrap a sublevel and reopen the wrapped sublevel', function (t) {
|
||||
const db = new NoopLevel()
|
||||
const sub1 = db.sublevel('test1')
|
||||
const sub2 = sub1.sublevel('test2')
|
||||
|
||||
sub2.once('open', function () {
|
||||
verify()
|
||||
|
||||
sub2.close(function (err) {
|
||||
t.ifError(err, 'no close error')
|
||||
|
||||
// Prefixes should be the same after closing & reopening
|
||||
// See https://github.com/Level/subleveldown/issues/78
|
||||
sub2.open(function (err) {
|
||||
t.ifError(err, 'no open error')
|
||||
verify()
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function verify () {
|
||||
t.is(sub1.prefix, '!test1!', 'sub1 prefix ok')
|
||||
t.ok(sub1.db instanceof NoopLevel)
|
||||
t.is(sub2.prefix, '!test1!!test2!', 'sub2 prefix ok')
|
||||
t.ok(sub2.db instanceof NoopLevel)
|
||||
}
|
||||
})
|
||||
|
||||
// Also test default fallback implementations of keys() and values()
|
||||
for (const [mode, def] of [['iterator', false], ['keys', false], ['values', false], ['keys', true], ['values', true]]) {
|
||||
const Ctor = mode === 'iterator' || def ? AbstractIterator : mode === 'keys' ? AbstractKeyIterator : AbstractValueIterator
|
||||
const privateMethod = def ? '_iterator' : '_' + mode
|
||||
const publicMethod = mode
|
||||
|
||||
t.test(`error from sublevel.${mode}() bubbles up (default implementation: ${def})`, function (t) {
|
||||
t.plan(2)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_next (callback) {
|
||||
this.nextTick(callback, new Error('next() error from parent database'))
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel({ encodings: { buffer: true } })
|
||||
const sub = db.sublevel('test')
|
||||
const it = sub[publicMethod]()
|
||||
|
||||
it.next(function (err) {
|
||||
t.is(err.message, 'next() error from parent database')
|
||||
|
||||
it.close(function () {
|
||||
t.pass('closed')
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('sublevel operations are prefixed', function (t) {
|
||||
t.test('sublevel.getMany() is prefixed', async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
_getMany (keys, options, callback) {
|
||||
t.same(keys, ['!test!a', '!test!b'])
|
||||
t.same(options, { keyEncoding: 'utf8', valueEncoding: 'utf8' })
|
||||
nextTick(callback, null, ['1', '2'])
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel({ encodings: { utf8: true } })
|
||||
const sub = db.sublevel('test')
|
||||
|
||||
await sub.open()
|
||||
await sub.getMany(['a', 'b'])
|
||||
})
|
||||
|
||||
// Also test default fallback implementations of keys() and values()
|
||||
for (const [mode, def] of [['iterator', false], ['keys', false], ['values', false], ['keys', true], ['values', true]]) {
|
||||
const Ctor = mode === 'iterator' || def ? AbstractIterator : mode === 'keys' ? AbstractKeyIterator : AbstractValueIterator
|
||||
const privateMethod = def ? '_iterator' : '_' + mode
|
||||
const publicMethod = mode
|
||||
|
||||
for (const deferred of [false, true]) {
|
||||
t.test(`sublevel ${mode}.seek() target is prefixed (default implementation: ${def}, deferred: ${deferred})`, async function (t) {
|
||||
t.plan(2)
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_seek (target, options) {
|
||||
t.is(target, '!sub!123')
|
||||
t.is(options.keyEncoding, 'utf8')
|
||||
}
|
||||
}
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel({ encodings: { utf8: true } })
|
||||
const sub = db.sublevel('sub', { keyEncoding: 'json' })
|
||||
|
||||
if (!deferred) await sub.open()
|
||||
|
||||
const it = sub[publicMethod]()
|
||||
it.seek(123)
|
||||
|
||||
if (deferred) await sub.open()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
t.test('sublevel.clear() is prefixed', async function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const calls = []
|
||||
class MockLevel extends AbstractLevel {
|
||||
_clear (options, callback) {
|
||||
calls.push(options)
|
||||
nextTick(callback)
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel({ encodings: { utf8: true } })
|
||||
const sub = db.sublevel('sub')
|
||||
|
||||
const test = async (options, expected) => {
|
||||
await sub.clear(options)
|
||||
t.same(calls.shift(), expected)
|
||||
}
|
||||
|
||||
await sub.open()
|
||||
|
||||
await test(undefined, {
|
||||
gte: '!sub!',
|
||||
lte: '!sub"',
|
||||
keyEncoding: 'utf8',
|
||||
reverse: false,
|
||||
limit: -1
|
||||
})
|
||||
|
||||
await test({ gt: 'a' }, {
|
||||
gt: '!sub!a',
|
||||
lte: '!sub"',
|
||||
keyEncoding: 'utf8',
|
||||
reverse: false,
|
||||
limit: -1
|
||||
})
|
||||
|
||||
await test({ gte: 'a', lt: 'x' }, {
|
||||
gte: '!sub!a',
|
||||
lt: '!sub!x',
|
||||
keyEncoding: 'utf8',
|
||||
reverse: false,
|
||||
limit: -1
|
||||
})
|
||||
|
||||
await test({ lte: 'x' }, {
|
||||
gte: '!sub!',
|
||||
lte: '!sub!x',
|
||||
keyEncoding: 'utf8',
|
||||
reverse: false,
|
||||
limit: -1
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('sublevel encodings', function (t) {
|
||||
// NOTE: adapted from subleveldown
|
||||
t.test('different sublevels can have different encodings', function (t) {
|
||||
t.plan(10)
|
||||
|
||||
const puts = []
|
||||
const gets = []
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
_put (key, value, { keyEncoding, valueEncoding }, callback) {
|
||||
puts.push({ key, value, keyEncoding, valueEncoding })
|
||||
nextTick(callback)
|
||||
}
|
||||
|
||||
_get (key, { keyEncoding, valueEncoding }, callback) {
|
||||
gets.push({ key, keyEncoding, valueEncoding })
|
||||
nextTick(callback, null, puts.shift().value)
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel({ encodings: { buffer: true, utf8: true } })
|
||||
const sub1 = db.sublevel('test1', { valueEncoding: 'json' })
|
||||
const sub2 = db.sublevel('test2', { keyEncoding: 'buffer', valueEncoding: 'buffer' })
|
||||
|
||||
sub1.put('foo', { some: 'json' }, function (err) {
|
||||
t.error(err, 'no error')
|
||||
|
||||
t.same(puts, [{
|
||||
key: '!test1!foo',
|
||||
value: '{"some":"json"}',
|
||||
keyEncoding: 'utf8',
|
||||
valueEncoding: 'utf8'
|
||||
}])
|
||||
|
||||
sub1.get('foo', function (err, value) {
|
||||
t.error(err, 'no error')
|
||||
t.same(value, { some: 'json' })
|
||||
t.same(gets.shift(), {
|
||||
key: '!test1!foo',
|
||||
keyEncoding: 'utf8',
|
||||
valueEncoding: 'utf8'
|
||||
})
|
||||
|
||||
sub2.put(Buffer.from([1, 2]), Buffer.from([3]), function (err) {
|
||||
t.error(err, 'no error')
|
||||
|
||||
t.same(puts, [{
|
||||
key: Buffer.from('!test2!\x01\x02'),
|
||||
value: Buffer.from([3]),
|
||||
keyEncoding: 'buffer',
|
||||
valueEncoding: 'buffer'
|
||||
}])
|
||||
|
||||
sub2.get(Buffer.from([1, 2]), function (err, value) {
|
||||
t.error(err, 'no error')
|
||||
t.same(value, Buffer.from([3]))
|
||||
t.same(gets.shift(), {
|
||||
key: Buffer.from('!test2!\x01\x02'),
|
||||
keyEncoding: 'buffer',
|
||||
valueEncoding: 'buffer'
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.test('sublevel indirectly supports transcoded encoding', function (t) {
|
||||
t.plan(5)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
_put (key, value, { keyEncoding, valueEncoding }, callback) {
|
||||
t.same({ key, value, keyEncoding, valueEncoding }, {
|
||||
key: Buffer.from('!test!foo'),
|
||||
value: Buffer.from('{"some":"json"}'),
|
||||
keyEncoding: 'buffer',
|
||||
valueEncoding: 'buffer'
|
||||
})
|
||||
nextTick(callback)
|
||||
}
|
||||
|
||||
_get (key, { keyEncoding, valueEncoding }, callback) {
|
||||
t.same({ key, keyEncoding, valueEncoding }, {
|
||||
key: Buffer.from('!test!foo'),
|
||||
keyEncoding: 'buffer',
|
||||
valueEncoding: 'buffer'
|
||||
})
|
||||
nextTick(callback, null, Buffer.from('{"some":"json"}'))
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel({ encodings: { buffer: true } })
|
||||
const sub = db.sublevel('test', { valueEncoding: 'json' })
|
||||
|
||||
sub.put('foo', { some: 'json' }, function (err) {
|
||||
t.error(err, 'no error')
|
||||
|
||||
sub.get('foo', function (err, value) {
|
||||
t.error(err, 'no error')
|
||||
t.same(value, { some: 'json' })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.test('concatenating sublevel Buffer keys', function (t) {
|
||||
t.plan(10)
|
||||
|
||||
const key = Buffer.from('00ff', 'hex')
|
||||
const prefixedKey = Buffer.concat([Buffer.from('!test!'), key])
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
_put (key, value, options, callback) {
|
||||
t.is(options.keyEncoding, 'buffer')
|
||||
t.is(options.valueEncoding, 'buffer')
|
||||
t.same(key, prefixedKey)
|
||||
t.same(value, Buffer.from('bar'))
|
||||
nextTick(callback)
|
||||
}
|
||||
|
||||
_get (key, options, callback) {
|
||||
t.is(options.keyEncoding, 'buffer')
|
||||
t.is(options.valueEncoding, 'buffer')
|
||||
t.same(key, prefixedKey)
|
||||
nextTick(callback, null, Buffer.from('bar'))
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel({ encodings: { buffer: true } })
|
||||
const sub = db.sublevel('test', { keyEncoding: 'buffer' })
|
||||
|
||||
sub.put(key, 'bar', function (err) {
|
||||
t.ifError(err)
|
||||
sub.get(key, function (err, value) {
|
||||
t.ifError(err)
|
||||
t.is(value, 'bar')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.test('concatenating sublevel Uint8Array keys', function (t) {
|
||||
t.plan(10)
|
||||
|
||||
const key = new Uint8Array([0, 255])
|
||||
const textEncoder = new TextEncoder()
|
||||
const prefix = textEncoder.encode('!test!')
|
||||
const prefixedKey = new Uint8Array(prefix.byteLength + key.byteLength)
|
||||
|
||||
prefixedKey.set(prefix, 0)
|
||||
prefixedKey.set(key, prefix.byteLength)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
_put (key, value, options, callback) {
|
||||
t.is(options.keyEncoding, 'view')
|
||||
t.is(options.valueEncoding, 'view')
|
||||
t.same(key, prefixedKey)
|
||||
t.same(value, textEncoder.encode('bar'))
|
||||
nextTick(callback)
|
||||
}
|
||||
|
||||
_get (key, options, callback) {
|
||||
t.is(options.keyEncoding, 'view')
|
||||
t.is(options.valueEncoding, 'view')
|
||||
t.same(key, prefixedKey)
|
||||
nextTick(callback, null, textEncoder.encode('bar'))
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel({ encodings: { view: true } })
|
||||
const sub = db.sublevel('test', { keyEncoding: 'view' })
|
||||
|
||||
sub.put(key, 'bar', function (err) {
|
||||
t.ifError(err)
|
||||
sub.get(key, function (err, value) {
|
||||
t.ifError(err)
|
||||
t.is(value, 'bar')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Also test default fallback implementations of keys() and values()
|
||||
for (const [mode, def] of [['iterator', false], ['keys', false], ['values', false], ['keys', true], ['values', true]]) {
|
||||
const Ctor = mode === 'iterator' || def ? AbstractIterator : mode === 'keys' ? AbstractKeyIterator : AbstractValueIterator
|
||||
const privateMethod = def ? '_iterator' : '_' + mode
|
||||
const publicMethod = mode
|
||||
|
||||
t.test(`unfixing sublevel.${mode}() Buffer keys (default implementation: ${def})`, function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const testKey = Buffer.from('00ff', 'hex')
|
||||
const prefixedKey = Buffer.concat([Buffer.from('!test!'), testKey])
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_next (callback) {
|
||||
if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, prefixedKey, 'bar')
|
||||
} else if (mode === 'keys') {
|
||||
this.nextTick(callback, null, prefixedKey)
|
||||
} else {
|
||||
this.nextTick(callback, null, 'bar')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
t.is(options.keyEncoding, 'buffer')
|
||||
t.is(options.valueEncoding, 'utf8')
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel({ encodings: { buffer: true, view: true, utf8: true } })
|
||||
const sub = db.sublevel('test', { keyEncoding: 'buffer' })
|
||||
|
||||
sub[publicMethod]().next(function (err, keyOrValue) {
|
||||
t.ifError(err)
|
||||
t.same(keyOrValue, mode === 'values' ? 'bar' : testKey)
|
||||
})
|
||||
})
|
||||
|
||||
t.test(`unfixing sublevel.${mode}() Uint8Array keys (default implementation: ${def})`, function (t) {
|
||||
t.plan(4)
|
||||
|
||||
const testKey = new Uint8Array([0, 255])
|
||||
const textEncoder = new TextEncoder()
|
||||
const prefix = textEncoder.encode('!test!')
|
||||
const prefixedKey = new Uint8Array(prefix.byteLength + testKey.byteLength)
|
||||
|
||||
prefixedKey.set(prefix, 0)
|
||||
prefixedKey.set(testKey, prefix.byteLength)
|
||||
|
||||
class MockIterator extends Ctor {
|
||||
_next (callback) {
|
||||
if (mode === 'iterator' || def) {
|
||||
this.nextTick(callback, null, prefixedKey, 'bar')
|
||||
} else if (mode === 'keys') {
|
||||
this.nextTick(callback, null, prefixedKey)
|
||||
} else {
|
||||
this.nextTick(callback, null, 'bar')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
[privateMethod] (options) {
|
||||
t.is(options.keyEncoding, 'view')
|
||||
t.is(options.valueEncoding, 'utf8')
|
||||
return new MockIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel({ encodings: { buffer: true, view: true, utf8: true } })
|
||||
const sub = db.sublevel('test', { keyEncoding: 'view' })
|
||||
|
||||
sub[publicMethod]().next(function (err, keyOrValue) {
|
||||
t.ifError(err)
|
||||
t.same(keyOrValue, mode === 'values' ? 'bar' : testKey)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
for (const chained of [false, true]) {
|
||||
for (const deferred of [false, true]) {
|
||||
test(`batch() with sublevel per operation (chained: ${chained}, deferred: ${deferred})`, async function (t) {
|
||||
t.plan(6)
|
||||
|
||||
class MockLevel extends AbstractLevel {
|
||||
_batch (operations, options, callback) {
|
||||
t.same(operations, [
|
||||
{
|
||||
type: 'put',
|
||||
sublevel: null,
|
||||
key: '!1!a',
|
||||
value: '{"foo":123}',
|
||||
keyEncoding: 'utf8',
|
||||
valueEncoding: 'utf8'
|
||||
},
|
||||
{
|
||||
type: 'put',
|
||||
sublevel: null,
|
||||
key: '!2!a-y',
|
||||
value: '[object Object]',
|
||||
keyEncoding: 'utf8',
|
||||
valueEncoding: 'utf8'
|
||||
},
|
||||
{
|
||||
type: 'put',
|
||||
sublevel: null,
|
||||
key: '!1!b',
|
||||
value: '[object Object]',
|
||||
keyEncoding: 'utf8',
|
||||
valueEncoding: 'utf8'
|
||||
},
|
||||
{
|
||||
type: 'put',
|
||||
sublevel: null,
|
||||
key: '!2!b',
|
||||
value: 'b',
|
||||
keyEncoding: 'utf8',
|
||||
valueEncoding: 'utf8'
|
||||
},
|
||||
{
|
||||
type: 'del',
|
||||
sublevel: null,
|
||||
key: '!2!c1',
|
||||
keyEncoding: 'utf8'
|
||||
},
|
||||
{
|
||||
type: 'del',
|
||||
sublevel: null,
|
||||
key: '!2!c2-y',
|
||||
keyEncoding: 'utf8'
|
||||
},
|
||||
{
|
||||
type: 'del',
|
||||
key: 'd-x',
|
||||
keyEncoding: 'utf8'
|
||||
}
|
||||
])
|
||||
t.same(options, {})
|
||||
nextTick(callback)
|
||||
}
|
||||
}
|
||||
|
||||
const db = new MockLevel({ encodings: { utf8: true } }, {
|
||||
keyEncoding: {
|
||||
encode: (key) => key + '-x',
|
||||
decode: (key) => key.slice(0, -2),
|
||||
name: 'x',
|
||||
format: 'utf8'
|
||||
}
|
||||
})
|
||||
|
||||
const sub1 = db.sublevel('1', { valueEncoding: 'json' })
|
||||
const sub2 = db.sublevel('2', {
|
||||
keyEncoding: {
|
||||
encode: (key) => key + '-y',
|
||||
decode: (key) => key.slice(0, -2),
|
||||
name: 'y',
|
||||
format: 'utf8'
|
||||
}
|
||||
})
|
||||
|
||||
if (!deferred) await sub1.open()
|
||||
|
||||
t.is(sub1.keyEncoding().name, 'utf8')
|
||||
t.is(sub1.valueEncoding().name, 'json')
|
||||
t.is(sub2.keyEncoding().name, 'y')
|
||||
t.is(sub2.valueEncoding().name, 'utf8')
|
||||
|
||||
if (chained) {
|
||||
await db.batch()
|
||||
// keyEncoding: utf8 (sublevel), valueEncoding: json (sublevel)
|
||||
.put('a', { foo: 123 }, { sublevel: sub1 })
|
||||
|
||||
// keyEncoding: y (sublevel), valueEncoding: utf8 (sublevel)
|
||||
.put('a', { foo: 123 }, { sublevel: sub2 })
|
||||
|
||||
// keyEncoding: utf8 (sublevel), valueEncoding: utf8 (operation)
|
||||
.put('b', { foo: 123 }, { sublevel: sub1, valueEncoding: 'utf8' })
|
||||
|
||||
// keyEncoding: utf8 (operation), valueEncoding: utf8 (sublevel)
|
||||
.put('b', 'b', { sublevel: sub2, keyEncoding: 'utf8' })
|
||||
|
||||
// keyEncoding: utf8 (operation)
|
||||
.del('c1', { sublevel: sub2, keyEncoding: 'utf8' })
|
||||
|
||||
// keyEncoding: y (sublevel)
|
||||
.del('c2', { sublevel: sub2 })
|
||||
|
||||
// keyEncoding: x (db). Should not affect sublevels.
|
||||
.del('d')
|
||||
.write()
|
||||
} else {
|
||||
await db.batch([
|
||||
{ type: 'put', sublevel: sub1, key: 'a', value: { foo: 123 } },
|
||||
{ type: 'put', sublevel: sub2, key: 'a', value: { foo: 123 } },
|
||||
{ type: 'put', sublevel: sub1, key: 'b', value: { foo: 123 }, valueEncoding: 'utf8' },
|
||||
{ type: 'put', sublevel: sub2, key: 'b', value: 'b', keyEncoding: 'utf8' },
|
||||
{ type: 'del', key: 'c1', sublevel: sub2, keyEncoding: 'utf8' },
|
||||
{ type: 'del', key: 'c2', sublevel: sub2 },
|
||||
{ type: 'del', key: 'd' }
|
||||
])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
108
node_modules/abstract-level/test/sublevel-test.js
generated
vendored
Normal file
108
node_modules/abstract-level/test/sublevel-test.js
generated
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
'use strict'
|
||||
|
||||
const { Buffer } = require('buffer')
|
||||
|
||||
exports.all = function (test, testCommon) {
|
||||
for (const deferred of [false, true]) {
|
||||
// NOTE: adapted from subleveldown
|
||||
test(`sublevel.clear() (deferred: ${deferred})`, async function (t) {
|
||||
const db = testCommon.factory()
|
||||
const sub1 = db.sublevel('1')
|
||||
const sub2 = db.sublevel('2')
|
||||
|
||||
if (!deferred) await sub1.open()
|
||||
if (!deferred) await sub2.open()
|
||||
|
||||
await populate([sub1, sub2], ['a', 'b'])
|
||||
await verify(['!1!a', '!1!b', '!2!a', '!2!b'])
|
||||
|
||||
await clear([sub1], {})
|
||||
await verify(['!2!a', '!2!b'])
|
||||
|
||||
await populate([sub1], ['a', 'b'])
|
||||
await clear([sub2], { lt: 'b' })
|
||||
await verify(['!1!a', '!1!b', '!2!b'])
|
||||
await db.close()
|
||||
|
||||
async function populate (subs, items) {
|
||||
return Promise.all(subs.map(sub => {
|
||||
return sub.batch(items.map(function (item) {
|
||||
return { type: 'put', key: item, value: item }
|
||||
}))
|
||||
}))
|
||||
}
|
||||
|
||||
async function clear (subs, opts) {
|
||||
return Promise.all(subs.map(sub => {
|
||||
return sub.clear(opts)
|
||||
}))
|
||||
}
|
||||
|
||||
async function verify (expected) {
|
||||
const keys = await db.keys().all()
|
||||
t.same(keys, expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
for (const deferred of [false, true]) {
|
||||
for (const keyEncoding of ['buffer', 'view']) {
|
||||
if (!testCommon.supports.encodings[keyEncoding]) return
|
||||
|
||||
// NOTE: adapted from subleveldown. See https://github.com/Level/subleveldown/issues/87
|
||||
test(`iterate sublevel keys with bytes above 196 (${keyEncoding}, deferred: ${deferred})`, async function (t) {
|
||||
const db = testCommon.factory()
|
||||
const sub1 = db.sublevel('a', { keyEncoding })
|
||||
const sub2 = db.sublevel('b', { keyEncoding })
|
||||
const length = (db) => db.keys().all().then(x => x.length)
|
||||
|
||||
if (!deferred) await sub1.open()
|
||||
if (!deferred) await sub2.open()
|
||||
|
||||
const batch1 = sub1.batch()
|
||||
const batch2 = sub2.batch()
|
||||
const keys = []
|
||||
|
||||
for (let i = 0; i < 256; i++) {
|
||||
const key = keyEncoding === 'buffer' ? Buffer.from([i]) : new Uint8Array([i])
|
||||
keys.push(key)
|
||||
batch1.put(key, 'aa')
|
||||
batch2.put(key, 'bb')
|
||||
}
|
||||
|
||||
await Promise.all([batch1.write(), batch2.write()])
|
||||
|
||||
const entries1 = await sub1.iterator().all()
|
||||
const entries2 = await sub2.iterator().all()
|
||||
|
||||
t.is(entries1.length, 256, 'sub1 yielded all entries')
|
||||
t.is(entries2.length, 256, 'sub2 yielded all entries')
|
||||
t.ok(entries1.every(x => x[1] === 'aa'))
|
||||
t.ok(entries2.every(x => x[1] === 'bb'))
|
||||
|
||||
const many1 = await sub1.getMany(keys)
|
||||
const many2 = await sub2.getMany(keys)
|
||||
|
||||
t.is(many1.length, 256, 'sub1 yielded all values')
|
||||
t.is(many2.length, 256, 'sub2 yielded all values')
|
||||
t.ok(many1.every(x => x === 'aa'))
|
||||
t.ok(many2.every(x => x === 'bb'))
|
||||
|
||||
const singles1 = await Promise.all(keys.map(k => sub1.get(k)))
|
||||
const singles2 = await Promise.all(keys.map(k => sub2.get(k)))
|
||||
|
||||
t.is(singles1.length, 256, 'sub1 yielded all values')
|
||||
t.is(singles2.length, 256, 'sub2 yielded all values')
|
||||
t.ok(singles1.every(x => x === 'aa'))
|
||||
t.ok(singles2.every(x => x === 'bb'))
|
||||
|
||||
await sub1.clear()
|
||||
|
||||
t.same(await length(sub1), 0, 'cleared sub1')
|
||||
t.same(await length(sub2), 256, 'did not clear sub2')
|
||||
|
||||
await db.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
280
node_modules/abstract-level/test/util.js
generated
vendored
Normal file
280
node_modules/abstract-level/test/util.js
generated
vendored
Normal file
@ -0,0 +1,280 @@
|
||||
'use strict'
|
||||
|
||||
const ModuleError = require('module-error')
|
||||
const { AbstractLevel, AbstractChainedBatch } = require('..')
|
||||
const { AbstractIterator, AbstractKeyIterator, AbstractValueIterator } = require('..')
|
||||
|
||||
const spies = []
|
||||
|
||||
exports.verifyNotFoundError = function (err) {
|
||||
return err.code === 'LEVEL_NOT_FOUND' && err.notFound === true && err.status === 404
|
||||
}
|
||||
|
||||
exports.illegalKeys = [
|
||||
{ name: 'null key', key: null },
|
||||
{ name: 'undefined key', key: undefined }
|
||||
]
|
||||
|
||||
exports.illegalValues = [
|
||||
{ name: 'null key', value: null },
|
||||
{ name: 'undefined value', value: undefined }
|
||||
]
|
||||
|
||||
/**
|
||||
* Wrap a callback to check that it's called asynchronously. Must be
|
||||
* combined with a `ctx()`, `with()` or `end()` call.
|
||||
*
|
||||
* @param {function} cb Callback to check.
|
||||
* @param {string} name Optional callback name to use in assertion messages.
|
||||
* @returns {function} Wrapped callback.
|
||||
*/
|
||||
exports.assertAsync = function (cb, name) {
|
||||
const spy = {
|
||||
called: false,
|
||||
name: name || cb.name || 'anonymous'
|
||||
}
|
||||
|
||||
spies.push(spy)
|
||||
|
||||
return function (...args) {
|
||||
spy.called = true
|
||||
return cb.apply(this, args)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that callbacks wrapped with `assertAsync()` were not yet called.
|
||||
* @param {import('tape').Test} t Tape test object.
|
||||
*/
|
||||
exports.assertAsync.end = function (t) {
|
||||
for (const { called, name } of spies.splice(0, spies.length)) {
|
||||
t.is(called, false, `callback (${name}) is asynchronous`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a test function to verify `assertAsync()` spies at the end.
|
||||
* @param {import('tape').TestCase} test Test function to be passed to `tape()`.
|
||||
* @returns {import('tape').TestCase} Wrapped test function.
|
||||
*/
|
||||
exports.assertAsync.ctx = function (test) {
|
||||
return function (...args) {
|
||||
const ret = test.call(this, ...args)
|
||||
exports.assertAsync.end(args[0])
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap an arbitrary callback to verify `assertAsync()` spies at the end.
|
||||
* @param {import('tape').Test} t Tape test object.
|
||||
* @param {function} cb Callback to wrap.
|
||||
* @returns {function} Wrapped callback.
|
||||
*/
|
||||
exports.assertAsync.with = function (t, cb) {
|
||||
return function (...args) {
|
||||
const ret = cb.call(this, ...args)
|
||||
exports.assertAsync.end(t)
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
exports.mockLevel = function (methods, ...args) {
|
||||
class TestLevel extends AbstractLevel {}
|
||||
for (const k in methods) TestLevel.prototype[k] = methods[k]
|
||||
if (!args.length) args = [{ encodings: { utf8: true } }]
|
||||
return new TestLevel(...args)
|
||||
}
|
||||
|
||||
exports.mockIterator = function (db, options, methods, ...args) {
|
||||
class TestIterator extends AbstractIterator {}
|
||||
for (const k in methods) TestIterator.prototype[k] = methods[k]
|
||||
return new TestIterator(db, options, ...args)
|
||||
}
|
||||
|
||||
exports.mockChainedBatch = function (db, methods, ...args) {
|
||||
class TestBatch extends AbstractChainedBatch {}
|
||||
for (const k in methods) TestBatch.prototype[k] = methods[k]
|
||||
return new TestBatch(db, ...args)
|
||||
}
|
||||
|
||||
// Mock encoding where null and undefined are significant types
|
||||
exports.nullishEncoding = {
|
||||
name: 'nullish',
|
||||
format: 'utf8',
|
||||
encode (v) {
|
||||
return v === null ? '\x00' : v === undefined ? '\xff' : String(v)
|
||||
},
|
||||
decode (v) {
|
||||
return v === '\x00' ? null : v === '\xff' ? undefined : v
|
||||
}
|
||||
}
|
||||
|
||||
const kEntries = Symbol('entries')
|
||||
const kPosition = Symbol('position')
|
||||
const kOptions = Symbol('options')
|
||||
|
||||
/**
|
||||
* A minimal and non-optimized implementation for use in tests. Only supports utf8.
|
||||
* Don't use this as a reference implementation.
|
||||
*/
|
||||
class MinimalLevel extends AbstractLevel {
|
||||
constructor (options) {
|
||||
super({ encodings: { utf8: true }, seek: true }, options)
|
||||
this[kEntries] = new Map()
|
||||
}
|
||||
|
||||
_put (key, value, options, callback) {
|
||||
this[kEntries].set(key, value)
|
||||
this.nextTick(callback)
|
||||
}
|
||||
|
||||
_get (key, options, callback) {
|
||||
const value = this[kEntries].get(key)
|
||||
|
||||
if (value === undefined) {
|
||||
return this.nextTick(callback, new ModuleError(`Key ${key} was not found`, {
|
||||
code: 'LEVEL_NOT_FOUND'
|
||||
}))
|
||||
}
|
||||
|
||||
this.nextTick(callback, null, value)
|
||||
}
|
||||
|
||||
_getMany (keys, options, callback) {
|
||||
const values = keys.map(k => this[kEntries].get(k))
|
||||
this.nextTick(callback, null, values)
|
||||
}
|
||||
|
||||
_del (key, options, callback) {
|
||||
this[kEntries].delete(key)
|
||||
this.nextTick(callback)
|
||||
}
|
||||
|
||||
_clear (options, callback) {
|
||||
for (const [k] of sliceEntries(this[kEntries], options, true)) {
|
||||
this[kEntries].delete(k)
|
||||
}
|
||||
|
||||
this.nextTick(callback)
|
||||
}
|
||||
|
||||
_batch (operations, options, callback) {
|
||||
const entries = new Map(this[kEntries])
|
||||
|
||||
for (const op of operations) {
|
||||
if (op.type === 'put') entries.set(op.key, op.value)
|
||||
else entries.delete(op.key)
|
||||
}
|
||||
|
||||
this[kEntries] = entries
|
||||
this.nextTick(callback)
|
||||
}
|
||||
|
||||
_iterator (options) {
|
||||
return new MinimalIterator(this, options)
|
||||
}
|
||||
|
||||
_keys (options) {
|
||||
return new MinimalKeyIterator(this, options)
|
||||
}
|
||||
|
||||
_values (options) {
|
||||
return new MinimalValueIterator(this, options)
|
||||
}
|
||||
}
|
||||
|
||||
class MinimalIterator extends AbstractIterator {
|
||||
constructor (db, options) {
|
||||
super(db, options)
|
||||
this[kEntries] = sliceEntries(db[kEntries], options, false)
|
||||
this[kOptions] = options
|
||||
this[kPosition] = 0
|
||||
}
|
||||
}
|
||||
|
||||
class MinimalKeyIterator extends AbstractKeyIterator {
|
||||
constructor (db, options) {
|
||||
super(db, options)
|
||||
this[kEntries] = sliceEntries(db[kEntries], options, false)
|
||||
this[kOptions] = options
|
||||
this[kPosition] = 0
|
||||
}
|
||||
}
|
||||
|
||||
class MinimalValueIterator extends AbstractValueIterator {
|
||||
constructor (db, options) {
|
||||
super(db, options)
|
||||
this[kEntries] = sliceEntries(db[kEntries], options, false)
|
||||
this[kOptions] = options
|
||||
this[kPosition] = 0
|
||||
}
|
||||
}
|
||||
|
||||
for (const Ctor of [MinimalIterator, MinimalKeyIterator, MinimalValueIterator]) {
|
||||
const mapEntry = Ctor === MinimalIterator ? e => e : Ctor === MinimalKeyIterator ? e => e[0] : e => e[1]
|
||||
|
||||
Ctor.prototype._next = function (callback) {
|
||||
const entry = this[kEntries][this[kPosition]++]
|
||||
if (entry === undefined) return this.nextTick(callback)
|
||||
if (Ctor === MinimalIterator) this.nextTick(callback, null, entry[0], entry[1])
|
||||
else this.nextTick(callback, null, mapEntry(entry))
|
||||
}
|
||||
|
||||
Ctor.prototype._nextv = function (size, options, callback) {
|
||||
const entries = this[kEntries].slice(this[kPosition], this[kPosition] + size)
|
||||
this[kPosition] += entries.length
|
||||
this.nextTick(callback, null, entries.map(mapEntry))
|
||||
}
|
||||
|
||||
Ctor.prototype._all = function (options, callback) {
|
||||
const end = this.limit - this.count + this[kPosition]
|
||||
const entries = this[kEntries].slice(this[kPosition], end)
|
||||
this[kPosition] = this[kEntries].length
|
||||
this.nextTick(callback, null, entries.map(mapEntry))
|
||||
}
|
||||
|
||||
Ctor.prototype._seek = function (target, options) {
|
||||
this[kPosition] = this[kEntries].length
|
||||
|
||||
if (!outOfRange(target, this[kOptions])) {
|
||||
// Don't care about performance here
|
||||
for (let i = 0; i < this[kPosition]; i++) {
|
||||
const key = this[kEntries][i][0]
|
||||
|
||||
if (this[kOptions].reverse ? key <= target : key >= target) {
|
||||
this[kPosition] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const outOfRange = function (target, options) {
|
||||
if ('gte' in options) {
|
||||
if (target < options.gte) return true
|
||||
} else if ('gt' in options) {
|
||||
if (target <= options.gt) return true
|
||||
}
|
||||
|
||||
if ('lte' in options) {
|
||||
if (target > options.lte) return true
|
||||
} else if ('lt' in options) {
|
||||
if (target >= options.lt) return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
const sliceEntries = function (entries, options, applyLimit) {
|
||||
entries = Array.from(entries)
|
||||
.filter((e) => !outOfRange(e[0], options))
|
||||
.sort((a, b) => a[0] > b[0] ? 1 : a[0] < b[0] ? -1 : 0)
|
||||
|
||||
if (options.reverse) entries.reverse()
|
||||
if (applyLimit && options.limit !== -1) entries = entries.slice(0, options.limit)
|
||||
|
||||
return entries
|
||||
}
|
||||
|
||||
exports.MinimalLevel = MinimalLevel
|
Reference in New Issue
Block a user