diff --git a/src/utils/settings.ts b/src/utils/settings.ts index 8dfcccf..785ae60 100644 --- a/src/utils/settings.ts +++ b/src/utils/settings.ts @@ -1,8 +1,9 @@ import fs from 'fs' -import { join } from 'path' -import { mergeDeepRight } from 'ramda' import yaml from 'js-yaml' +import { extname, join } from 'path' +import { mergeDeepRight } from 'ramda' + import { createLogger } from '../factories/logger-factory' import { ISettings } from '../@types/settings' @@ -25,7 +26,7 @@ export class SettingsStatic { } public static loadAndParseYamlFile(path: string): ISettings { - const defaultSettingsFileContent = fs.readFileSync(path, 'utf8') + const defaultSettingsFileContent = fs.readFileSync(path, { encoding: 'utf-8' }) const defaults = yaml.load(defaultSettingsFileContent) as ISettings return defaults } @@ -40,9 +41,10 @@ export class SettingsStatic { } public static settingsFileType(path) { - const files = fs.readdirSync(path).filter(fn => fn.startsWith('settings')) - if (files.length) { - const extension = files.pop().split('.')[1] + const files: string[] = fs.readdirSync(path) + const filteredFiles = files ? files.filter(fn => fn.startsWith('settings')) : [] + if (filteredFiles.length) { + const extension = extname(filteredFiles.pop()) return FileType[extension] } else { return null diff --git a/test/unit/utils/settings.spec.ts b/test/unit/utils/settings.spec.ts index e5197ba..204de8e 100644 --- a/test/unit/utils/settings.spec.ts +++ b/test/unit/utils/settings.spec.ts @@ -1,6 +1,5 @@ import { expect } from 'chai' import fs from 'fs' -import { homedir } from 'os' import { join } from 'path' import Sinon from 'sinon' @@ -20,15 +19,15 @@ describe('SettingsStatic', () => { }) it('returns string ending with .nostr/ by default', () => { - expect(SettingsStatic.getSettingsFileBasePath()).to.be.a('string').and.to.match(/s\.nostr$/) + expect(SettingsStatic.getSettingsFileBasePath()).to.be.a('string').and.to.match(/.nostr/) }) it('returns path begins with user\'s home dir by default', () => { - expect(SettingsStatic.getSettingsFileBasePath()).to.be.a('string').and.equal(`${join(homedir(), '.nostr')}/`) + expect(SettingsStatic.getSettingsFileBasePath()).to.be.a('string').and.equal(`${join(process.cwd(), '.nostr')}`) }) it('returns path with NOSTR_CONFIG_DIR if set', () => { - process.env.NOSTR_CONFIG_DIR = '/some/path' + process.env.NOSTR_CONFIG_DIR = '/some/path/' expect(SettingsStatic.getSettingsFileBasePath()).to.be.a('string').and.equal('/some/path/') }) @@ -51,13 +50,76 @@ describe('SettingsStatic', () => { }) it('returns path begins with user\'s home dir by default', () => { - expect(SettingsStatic.getDefaultSettingsFilePath()).to.be.a('string').and.equal(`${join(homedir(), '.nostr')}/settings.yaml`) + expect(SettingsStatic.getDefaultSettingsFilePath()).to.be.a('string').and.equal(`${join(process.cwd(), '/resources')}/default-settings.yaml`) + }) + }) + + describe('.loadAndParseYamlFile', () => { + let readFileSyncStub: Sinon.SinonStub + + beforeEach(() => { + readFileSyncStub = Sinon.stub(fs, 'readFileSync') }) - it('returns path with NOSTR_CONFIG_DIR if set', () => { - process.env.NOSTR_CONFIG_DIR = '/some/path' + afterEach(() => { + readFileSyncStub.restore() + }) - expect(SettingsStatic.getDefaultSettingsFilePath()).to.be.a('string').and.equal('/some/path/settings.yaml') + it('loads and parses yaml file from given path', () => { + readFileSyncStub.returns('"content"') + + expect(SettingsStatic.loadAndParseYamlFile('/some/path/file.yaml')).to.equal('content') + + expect(readFileSyncStub).to.have.been.calledOnceWithExactly( + '/some/path/file.yaml', + { encoding: 'utf-8' } + ) + }) + }) + + describe('.loadAndParseJsonFile', () => { + let readFileSyncStub: Sinon.SinonStub + + beforeEach(() => { + readFileSyncStub = Sinon.stub(fs, 'readFileSync') + }) + + afterEach(() => { + readFileSyncStub.restore() + }) + + it('loads and parses json file from given path', () => { + readFileSyncStub.returns('"content"') + + expect(SettingsStatic.loadAndParseJsonFile('/some/path/file.json')).to.equal('content') + + expect(readFileSyncStub).to.have.been.calledOnceWithExactly( + '/some/path/file.json', + { encoding: 'utf-8' } + ) + }) + }) + + describe('.settingsFileType', () => { + let readFileSyncStub: Sinon.SinonStub + + beforeEach(() => { + readFileSyncStub = Sinon.stub(fs, 'readFileSync') + }) + + afterEach(() => { + readFileSyncStub.restore() + }) + + it('gets file type by looking for settings file in config dir', () => { + readFileSyncStub.returns('{\n"key": "value"\n}') + + expect(SettingsStatic.loadAndParseJsonFile('/some/path/file.json')).to.have.property('key', 'value') + + expect(readFileSyncStub).to.have.been.calledOnceWithExactly( + '/some/path/file.json', + { encoding: 'utf-8' }, + ) }) }) @@ -86,7 +148,11 @@ describe('SettingsStatic', () => { describe('.createSettings', () => { let existsSyncStub: Sinon.SinonStub - let getSettingsFilePathStub: Sinon.SinonStub + let mkdirSyncStub: Sinon.SinonStub + let readdirSyncStub: Sinon.SinonStub + let getSettingsFileBasePathStub: Sinon.SinonStub + let getDefaultSettingsFilePathStub: Sinon.SinonStub + let settingsFileTypeStub: Sinon.SinonStub let saveSettingsStub: Sinon.SinonStub let loadSettingsStub: Sinon.SinonStub @@ -98,7 +164,11 @@ describe('SettingsStatic', () => { sandbox = Sinon.createSandbox() existsSyncStub = sandbox.stub(fs, 'existsSync') - getSettingsFilePathStub = sandbox.stub(SettingsStatic, 'getSettingsFileBasePath') + mkdirSyncStub = sandbox.stub(fs, 'mkdirSync') + readdirSyncStub = sandbox.stub(fs, 'readdirSync') + getSettingsFileBasePathStub = sandbox.stub(SettingsStatic, 'getSettingsFileBasePath') + getDefaultSettingsFilePathStub = sandbox.stub(SettingsStatic, 'getDefaultSettingsFilePath') + settingsFileTypeStub = sandbox.stub(SettingsStatic, 'settingsFileType') saveSettingsStub = sandbox.stub(SettingsStatic, 'saveSettings') loadSettingsStub = sandbox.stub(SettingsStatic, 'loadSettings') }) @@ -107,61 +177,72 @@ describe('SettingsStatic', () => { sandbox.restore() }) - it('creates settings from default if settings file is missing', () => { - getSettingsFilePathStub.returns('/some/path/settings.json') + it('creates settings from defaults if settings file is missing', () => { + getSettingsFileBasePathStub.returns('/some/path/settings.yaml') existsSyncStub.returns(false) + mkdirSyncStub.returns(true) + readdirSyncStub.returns(['file.yaml']) + loadSettingsStub.returns({}) expect(SettingsStatic.createSettings()).to.be.an('object') - expect(existsSyncStub).to.have.been.calledOnceWithExactly('/some/path/settings.json') - expect(getSettingsFilePathStub).to.have.been.calledOnce + expect(existsSyncStub).to.have.been.calledOnceWithExactly('/some/path/settings.yaml') + expect(getSettingsFileBasePathStub).to.have.been.calledOnce expect(saveSettingsStub).to.have.been.calledOnceWithExactly( - '/some/path/settings.json', + '/some/path/settings.yaml', Sinon.match.object, ) - expect(loadSettingsStub).not.to.have.been.called + expect(loadSettingsStub).to.have.been.called }) it('returns default settings if saving settings file throws', () => { const error = new Error('mistakes were made') - getSettingsFilePathStub.returns('/some/path/settings.json') + getSettingsFileBasePathStub.returns('/some/path/settings.json') saveSettingsStub.throws(error) existsSyncStub.returns(false) + readdirSyncStub.returns(['file.yaml']) + loadSettingsStub.returns({}) expect(SettingsStatic.createSettings()).to.be.an('object') expect(existsSyncStub).to.have.been.calledOnceWithExactly('/some/path/settings.json') - expect(getSettingsFilePathStub).to.have.been.calledOnce + expect(getSettingsFileBasePathStub).to.have.been.calledOnce expect(saveSettingsStub).to.have.been.calledOnceWithExactly( '/some/path/settings.json', Sinon.match.object, ) - expect(loadSettingsStub).not.to.have.been.called + expect(loadSettingsStub).to.have.been.called }) - it('loads settings from file if settings file is exists', () => { - loadSettingsStub.returns({}) - getSettingsFilePathStub.returns('/some/path/settings.json') + it('loads settings from file if settings file exists', () => { + loadSettingsStub.returns({ test: 'value' }) + getSettingsFileBasePathStub.returns('/some/path/settings.yaml') + getDefaultSettingsFilePathStub.returns('/some/path/settings.yaml') existsSyncStub.returns(true) + readdirSyncStub.returns(['settings.yaml']) + settingsFileTypeStub.returns('yaml') + expect(SettingsStatic.createSettings()).to.be.an('object') - expect(existsSyncStub).to.have.been.calledOnceWithExactly('/some/path/settings.json') - expect(getSettingsFilePathStub).to.have.been.calledOnce + expect(existsSyncStub).to.have.been.calledWithExactly('/some/path/settings.yaml') + expect(getSettingsFileBasePathStub).to.have.been.calledOnce expect(saveSettingsStub).not.to.have.been.called - expect(loadSettingsStub).to.have.been.calledOnceWithExactly('/some/path/settings.json') + expect(loadSettingsStub).to.have.been.calledWithExactly('/some/path/settings.yaml', 'yaml') }) it('returns defaults if loading settings file throws', () => { const error = new Error('mistakes were made') loadSettingsStub.throws(error) - getSettingsFilePathStub.returns('/some/path/settings.json') + getSettingsFileBasePathStub.returns('/some/path/settings.json') + getDefaultSettingsFilePathStub.returns('/some/path/settings.yaml') existsSyncStub.returns(true) + readdirSyncStub.returns(['file.yaml']) expect(SettingsStatic.createSettings()).to.be.an('object') expect(existsSyncStub).to.have.been.calledOnceWithExactly('/some/path/settings.json') - expect(getSettingsFilePathStub).to.have.been.calledOnce + expect(getSettingsFileBasePathStub).to.have.been.calledOnce expect(saveSettingsStub).not.to.have.been.called expect(loadSettingsStub).to.have.been.calledOnceWithExactly('/some/path/settings.json') }) @@ -172,7 +253,7 @@ describe('SettingsStatic', () => { expect(SettingsStatic.createSettings()).to.equal(cachedSettings) - expect(getSettingsFilePathStub).not.to.have.been.calledOnce + expect(getSettingsFileBasePathStub).not.to.have.been.calledOnce expect(existsSyncStub).not.to.have.been.called expect(saveSettingsStub).not.to.have.been.called expect(loadSettingsStub).not.to.have.been.called @@ -191,11 +272,11 @@ describe('SettingsStatic', () => { }) it('saves settings to given path', () => { - SettingsStatic.saveSettings('/some/path/settings.json', {key: 'value'} as any) + SettingsStatic.saveSettings('/some/path', {key: 'value'} as any) expect(writeFileSyncStub).to.have.been.calledOnceWithExactly( - '/some/path/settings.json', - '{\n "key": "value"\n}', + '/some/path/settings.yaml', + Sinon.match.string, { encoding: 'utf-8' } ) })