More development
continuous-integration/appveyor/branch AppVeyor build succeeded Details

master
Jonatan Nilsson 2022-01-18 11:48:35 +00:00
parent 17830d7f8d
commit 0948885671
5 changed files with 174 additions and 19 deletions

View File

@ -1,5 +1,6 @@
import { Low, JSONFile } from 'lowdb'
import { type } from 'os'
import { defaults, isObject } from './defaults.mjs'
export default function GetDB(util, log, filename = 'db.json') {
let fullpath = util.getPathFromRoot('./' + filename)
@ -60,33 +61,31 @@ export default function GetDB(util, log, filename = 'db.json') {
}
return false
}
db.addApplication = function(name) {
db.data.core[name] ||= {}
defaults(db.data.core[name], {
active: null,
latestInstalled: null,
latestVersion: null,
versions: [],
})
}
return db.read()
.then(function() {
db.data ||= {
core: {
app: {
active: null,
latestInstalled: null,
latestVersion: null,
versions: [],
},
manager: {
active: null,
latestInstalled: null,
latestVersion: null,
versions: [],
},
version: 1,
}
if (!isObject(db.data)) {
log.warn(`File ${fullpath} was empty or not a json object, clearing it.`)
db.data = {}
}
defaults(db.data, { core: { version: 1 } })
return db.write()
})
.then(
function() { return db },
function(err) {
let wrapped = new Error(`Error writing to ${fullpath}: ${err.code}`)
let wrapped = new Error(`Error writing to ${fullpath}: ${err.message} (${err.code})`)
wrapped.code = err.code
throw wrapped
}

25
core/defaults.mjs Normal file
View File

@ -0,0 +1,25 @@
// taken from isobject npm library
export function isObject(val) {
return val != null && typeof val === 'object' && Array.isArray(val) === false
}
export function defaults(original, def) {
if (!isObject(original)) throw new Error('defaults called with non-object type')
Object.keys(original).forEach(key => {
if (isObject(original[key]) && def && isObject(def[key])) {
defaults(original[key], def[key])
}
})
if (def) {
Object.keys(def).forEach(function(key) {
if (typeof original[key] === 'undefined') {
original[key] = def[key]
}
})
}
return original
}

View File

@ -6,6 +6,7 @@ import Util from '../core/util.mjs'
var util = new Util(import.meta.url)
var logger = {
info: stub(),
warn: stub(),
error: stub(),
}
@ -28,10 +29,76 @@ t.test('Should auto create file with some defaults', async function() {
assert.ok(stat.size > 0)
assert.ok(db.data.core)
assert.ok(db.data.core.version)
assert.notOk(db.data.core.app)
assert.notOk(db.data.core.manager)
})
t.test('Should apply defaults to existing file', async function() {
await assert.isRejected(fs.stat('./test/db_test.json'))
await fs.writeFile('./test/db_test.json', '{"test":true}')
let db = await lowdb(util, logger, 'db_test.json')
let stat = await fs.stat('./test/db_test.json')
assert.ok(stat.size > 0)
assert.ok(db.data.core)
assert.ok(db.data.core.version)
assert.strictEqual(db.data.test, true)
assert.notOk(db.data.core.app)
assert.notOk(db.data.core.manager)
})
t.test('Should not fail if db is invalid', async function() {
logger.warn.reset()
await assert.isRejected(fs.stat('./test/db_test.json'))
await fs.writeFile('./test/db_test.json', '[]')
let db = await lowdb(util, logger, 'db_test.json')
let stat = await fs.stat('./test/db_test.json')
assert.ok(stat.size > 0)
assert.ok(db.data.core)
assert.ok(db.data.core.version)
assert.notOk(db.data.core.app)
assert.notOk(db.data.core.manager)
assert.ok(logger.warn.called)
assert.match(logger.warn.firstCall[0], /db_test.json/i)
assert.match(logger.warn.firstCall[0], /clear/i)
})
t.test('Should support adding an application with defaults', async function() {
await assert.isRejected(fs.stat('./test/db_test.json'))
let db = await lowdb(util, logger, 'db_test.json')
let stat = await fs.stat('./test/db_test.json')
assert.ok(stat.size > 0)
assert.ok(db.data.core)
assert.ok(db.data.core.version)
assert.notOk(db.data.core.app)
assert.notOk(db.data.core.manager)
db.addApplication('app')
assert.ok(db.data.core.app)
assert.ok(db.data.core.app.versions)
assert.ok(db.data.core.manager)
assert.ok(db.data.core.manager.versions)
assert.strictEqual(db.data.core.app.active, null)
assert.strictEqual(db.data.core.app.latestInstalled, null)
assert.strictEqual(db.data.core.app.latestVersion, null)
assert.notOk(db.data.core.herpderp)
db.addApplication('herpderp')
assert.ok(db.data.core.herpderp)
assert.ok(db.data.core.herpderp.versions)
assert.strictEqual(db.data.core.herpderp.active, null)
assert.strictEqual(db.data.core.herpderp.latestInstalled, null)
assert.strictEqual(db.data.core.herpderp.latestVersion, null)
})
t.test('Should support reading from db', async function() {

64
test/defaults.test.mjs Normal file
View File

@ -0,0 +1,64 @@
import { Eltro as t, assert} from 'eltro'
import { isObject, defaults } from '../core/defaults.mjs'
t.describe('#isObject()', () => {
t.test('should return false for invalid objects', function() {
let tests = [
[],
'',
'asdf',
12341,
0,
]
tests.forEach(function(check) {
assert.strictEqual(isObject(check), false)
})
})
t.test('should return true for valid objects', function() {
let tests = [
{},
new Object(),
]
tests.forEach(function(check) {
assert.strictEqual(isObject(check), true)
})
})
})
t.describe('#defaults()', () => {
t.test('should throw if original is missing or invalid', () => {
assert.throws(function() { defaults() })
assert.throws(function() { defaults('asdf') })
assert.throws(function() { defaults('') })
assert.throws(function() { defaults(null) })
assert.throws(function() { defaults(1234) })
assert.throws(function() { defaults([]) })
})
t.test('should not override existing variables', () => {
let assertOutput = { a: 2 }
defaults(assertOutput, { a: 1 })
assert.deepStrictEqual(assertOutput, { a: 2 })
})
t.test('should allow nesting through objects', () => {
let def = { a: { b: 2 } }
let inside = { a: { c: 3} }
defaults(inside, def)
assert.deepStrictEqual(inside.a, {
b: 2,
c: 3,
})
})
t.test('should not return new reference', () => {
let assertInput = { a: 1 }
let existing = assertInput
defaults(assertInput, { b: 2 })
assert.strictEqual(assertInput, existing)
})
})

0
test/updater.test.mjs Normal file
View File