better-sqlite3/test/10.database.open.js
2022-01-18 20:15:14 -06:00

187 lines
8.4 KiB
JavaScript

'use strict';
const fs = require('fs');
const path = require('path');
const Database = require('../.');
describe('new Database()', function () {
afterEach(function () {
if (this.db) this.db.close();
});
it('should throw when given invalid argument types', function () {
expect(() => (this.db = new Database('', ''))).to.throw(TypeError);
expect(() => (this.db = new Database({}, ''))).to.throw(TypeError);
expect(() => (this.db = new Database({}, {}))).to.throw(TypeError);
expect(() => (this.db = new Database({}))).to.throw(TypeError);
expect(() => (this.db = new Database(0))).to.throw(TypeError);
expect(() => (this.db = new Database(123))).to.throw(TypeError);
expect(() => (this.db = new Database(new String(util.next())))).to.throw(TypeError);
expect(() => (this.db = new Database(() => util.next()))).to.throw(TypeError);
expect(() => (this.db = new Database([util.next()]))).to.throw(TypeError);
});
it('should throw when boolean options are provided as non-booleans', function () {
expect(() => (this.db = new Database(util.next(), { readOnly: false }))).to.throw(TypeError);
expect(() => (this.db = new Database(util.next(), { readonly: undefined }))).to.throw(TypeError);
expect(() => (this.db = new Database(util.next(), { fileMustExist: undefined }))).to.throw(TypeError);
});
it('should allow anonymous temporary databases to be created', function () {
for (const args of [[''], [], [null], [undefined], ['', { timeout: 2000 }]]) {
const db = this.db = new Database(...args);
expect(db.name).to.equal('');
expect(db.memory).to.be.true;
expect(db.readonly).to.be.false;
expect(db.open).to.be.true;
expect(db.inTransaction).to.be.false;
expect(fs.existsSync('')).to.be.false;
expect(fs.existsSync('null')).to.be.false;
expect(fs.existsSync('undefined')).to.be.false;
expect(fs.existsSync('[object Object]')).to.be.false;
db.close();
}
});
it('should allow anonymous in-memory databases to be created', function () {
const db = this.db = new Database(':memory:');
expect(db.name).to.equal(':memory:');
expect(db.memory).to.be.true;
expect(db.readonly).to.be.false;
expect(db.open).to.be.true;
expect(db.inTransaction).to.be.false;
expect(fs.existsSync(':memory:')).to.be.false;
});
it('should allow disk-bound databases to be created', function () {
expect(fs.existsSync(util.next())).to.be.false;
const db = this.db = new Database(util.current());
expect(db.name).to.equal(util.current());
expect(db.memory).to.be.false;
expect(db.readonly).to.be.false;
expect(db.open).to.be.true;
expect(db.inTransaction).to.be.false;
expect(fs.existsSync(util.current())).to.be.true;
});
it('should allow readonly database connections to be created', function () {
expect(fs.existsSync(util.next())).to.be.false;
expect(() => (this.db = new Database(util.current(), { readonly: true }))).to.throw(Database.SqliteError).with.property('code', 'SQLITE_CANTOPEN');
(new Database(util.current())).close();
expect(fs.existsSync(util.current())).to.be.true;
const db = this.db = new Database(util.current(), { readonly: true });
expect(db.name).to.equal(util.current());
expect(db.memory).to.be.false;
expect(db.readonly).to.be.true;
expect(db.open).to.be.true;
expect(db.inTransaction).to.be.false;
expect(fs.existsSync(util.current())).to.be.true;
});
it('should not allow the "readonly" option for in-memory databases', function () {
expect(fs.existsSync(util.next())).to.be.false;
expect(() => (this.db = new Database(':memory:', { readonly: true }))).to.throw(TypeError);
expect(() => (this.db = new Database('', { readonly: true }))).to.throw(TypeError);
expect(fs.existsSync(util.current())).to.be.false;
});
it('should accept the "fileMustExist" option', function () {
expect(fs.existsSync(util.next())).to.be.false;
expect(() => (this.db = new Database(util.current(), { fileMustExist: true }))).to.throw(Database.SqliteError).with.property('code', 'SQLITE_CANTOPEN');
(new Database(util.current())).close();
expect(fs.existsSync(util.current())).to.be.true;
const db = this.db = new Database(util.current(), { fileMustExist: true });
expect(db.name).to.equal(util.current());
expect(db.memory).to.be.false;
expect(db.readonly).to.be.false;
expect(db.open).to.be.true;
expect(db.inTransaction).to.be.false;
expect(fs.existsSync(util.current())).to.be.true;
});
util.itUnix('should accept the "timeout" option', function () {
this.slow(4000);
const testTimeout = (timeout) => {
const db = new Database(util.current(), { timeout });
try {
const start = Date.now();
expect(() => db.exec('BEGIN EXCLUSIVE')).to.throw(Database.SqliteError).with.property('code', 'SQLITE_BUSY');
const end = Date.now();
expect(end - start).to.be.closeTo(timeout, 200);
} finally {
db.close();
}
};
const blocker = this.db = new Database(util.next(), { timeout: 0x7fffffff });
blocker.exec('BEGIN EXCLUSIVE');
testTimeout(0);
testTimeout(1000);
blocker.close();
expect(() => (this.db = new Database(util.current(), { timeout: undefined }))).to.throw(TypeError);
expect(() => (this.db = new Database(util.current(), { timeout: null }))).to.throw(TypeError);
expect(() => (this.db = new Database(util.current(), { timeout: NaN }))).to.throw(TypeError);
expect(() => (this.db = new Database(util.current(), { timeout: '75' }))).to.throw(TypeError);
expect(() => (this.db = new Database(util.current(), { timeout: -1 }))).to.throw(TypeError);
expect(() => (this.db = new Database(util.current(), { timeout: 75.01 }))).to.throw(TypeError);
expect(() => (this.db = new Database(util.current(), { timeout: 0x80000000 }))).to.throw(RangeError);
});
it('should accept the "nativeBinding" option', function () {
this.slow(500);
const oldBinding = require('bindings')({ bindings: 'better_sqlite3.node', path: true });
const newBinding = path.join(path.dirname(oldBinding), 'test.node');
expect(oldBinding).to.be.a('string');
fs.copyFileSync(oldBinding, newBinding);
const getBinding = db => db[Object.getOwnPropertySymbols(db)[0]].constructor;
let db1;
let db2;
let db3;
try {
db1 = new Database('');
db2 = new Database('', { nativeBinding: oldBinding });
db3 = new Database('', { nativeBinding: newBinding });
expect(db1.open).to.be.true;
expect(db2.open).to.be.true;
expect(db3.open).to.be.true;
expect(getBinding(db1)).to.equal(getBinding(db2));
expect(getBinding(db1)).to.not.equal(getBinding(db3));
expect(getBinding(db2)).to.not.equal(getBinding(db3));
} finally {
if (db1) db1.close();
if (db2) db2.close();
if (db3) db3.close();
}
});
it('should throw an Error if the directory does not exist', function () {
expect(fs.existsSync(util.next())).to.be.false;
const filepath = `temp/nonexistent/abcfoobar123/${util.current()}`;
expect(() => (this.db = new Database(filepath))).to.throw(TypeError);
expect(fs.existsSync(filepath)).to.be.false;
expect(fs.existsSync(util.current())).to.be.false;
});
it('should have a proper prototype chain', function () {
const db = this.db = new Database(util.next());
expect(db).to.be.an.instanceof(Database);
expect(db.constructor).to.equal(Database);
expect(Database.prototype.constructor).to.equal(Database);
expect(Database.prototype.close).to.be.a('function');
expect(Database.prototype.close).to.equal(db.close);
expect(Database.prototype).to.equal(Object.getPrototypeOf(db));
});
it('should work properly when called as a function', function () {
const db = this.db = Database(util.next());
expect(db).to.be.an.instanceof(Database);
expect(db.constructor).to.equal(Database);
expect(Database.prototype.close).to.equal(db.close);
expect(Database.prototype).to.equal(Object.getPrototypeOf(db));
});
it('should work properly when subclassed', function () {
class MyDatabase extends Database {
foo() {
return 999;
}
}
const db = this.db = new MyDatabase(util.next());
expect(db).to.be.an.instanceof(Database);
expect(db).to.be.an.instanceof(MyDatabase);
expect(db.constructor).to.equal(MyDatabase);
expect(Database.prototype.close).to.equal(db.close);
expect(MyDatabase.prototype.close).to.equal(db.close);
expect(Database.prototype.foo).to.be.undefined;
expect(MyDatabase.prototype.foo).to.equal(db.foo);
expect(Database.prototype).to.equal(Object.getPrototypeOf(MyDatabase.prototype));
expect(MyDatabase.prototype).to.equal(Object.getPrototypeOf(db));
expect(db.foo()).to.equal(999);
});
});