diff --git a/src/compile/build.ts b/src/compile/build.ts index bdb5f84c7..d8b73ef81 100644 --- a/src/compile/build.ts +++ b/src/compile/build.ts @@ -142,6 +142,7 @@ async function build(skipSelection: boolean = false, rootFile: string | undefine */ async function buildLoop() { if (isBuilding) { + logger.log('Another build loop is already running.') return } @@ -155,16 +156,15 @@ async function buildLoop() { if (step === undefined) { break } - lw.compile.lastSteps.push(step) const env = spawnProcess(step) const success = await monitorProcess(step, env) - skipped = skipped && !(step.isExternal || !step.isSkipped) + skipped = skipped && !step.isExternal && step.isSkipped if (success && queue.isLastStep(step)) { await afterSuccessfulBuilt(step, skipped) } } isBuilding = false - setTimeout(() => lw.compile.compiledPDFWriting--, 1000) + setTimeout(() => lw.compile.compiledPDFWriting--, vscode.workspace.getConfiguration('latex-workshop').get('latex.watch.pdf.delay') as number) } /** diff --git a/src/compile/index.ts b/src/compile/index.ts index 84b7b40e8..b063dca8c 100644 --- a/src/compile/index.ts +++ b/src/compile/index.ts @@ -1,5 +1,4 @@ import type { ChildProcess } from 'child_process' -import type { Step } from '../types' import { build, autoBuild } from './build' import { terminate } from './terminate' @@ -7,7 +6,6 @@ export const compile = { build, autoBuild, terminate, - lastSteps: [] as Step[], lastAutoBuildTime: 0, compiledPDFPath: '', compiledPDFWriting: 0, diff --git a/src/compile/recipe.ts b/src/compile/recipe.ts index 2b712bd3e..84ca45e49 100644 --- a/src/compile/recipe.ts +++ b/src/compile/recipe.ts @@ -303,8 +303,8 @@ function findRecipe(rootFile: string, langId: string, recipeName?: string): Reci } } // Find default recipe of last used - if (recipe === undefined && defaultRecipeName === 'lastUsed' && recipes.find(candidate => candidate.name === state.prevRecipe?.name)) { - recipe = state.prevRecipe + if (recipe === undefined && defaultRecipeName === 'lastUsed') { + recipe = recipes.find(candidate => candidate.name === state.prevRecipe?.name) } // If still not found, fallback to 'first' if (recipe === undefined) { diff --git a/test/suites/utils.ts b/test/suites/utils.ts index 165feafe3..6f51dbe51 100644 --- a/test/suites/utils.ts +++ b/test/suites/utils.ts @@ -79,7 +79,6 @@ export function sleep(ms: number) { export async function reset() { await vscode.commands.executeCommand('workbench.action.closeAllEditors') await Promise.all(Object.values(lw.cache.promises)) - lw.compile.lastSteps = [] lw.compile.lastAutoBuildTime = 0 lw.compile.compiledPDFPath = '' lw.compile.compiledPDFWriting = 0 diff --git a/test/units/01_core_file.test.ts b/test/units/01_core_file.test.ts index d80a29b38..a6ab7ddba 100644 --- a/test/units/01_core_file.test.ts +++ b/test/units/01_core_file.test.ts @@ -10,7 +10,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { const fixture = path.basename(__filename).split('.')[0] before(() => { - mock.object(lw, 'file') + mock.init(lw, 'file') }) after(() => { @@ -79,82 +79,82 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { assert.pathStrictEqual(lw.file.getOutDir(texPath), rootDir) }) - it('should get output directory with absolute `latex.outDir` and root', async () => { - await set.config('latex.outDir', '/output') + it('should get output directory with absolute `latex.outDir` and root', () => { + set.config('latex.outDir', '/output') set.root(fixture, 'main.tex') assert.pathStrictEqual(lw.file.getOutDir(), '/output') }) - it('should get output directory with relative `latex.outDir` and root', async () => { - await set.config('latex.outDir', 'output') + it('should get output directory with relative `latex.outDir` and root', () => { + set.config('latex.outDir', 'output') set.root(fixture, 'main.tex') assert.pathStrictEqual(lw.file.getOutDir(), 'output') }) - it('should get output directory with relative `latex.outDir` with leading `./` and root', async () => { - await set.config('latex.outDir', './output') + it('should get output directory with relative `latex.outDir` with leading `./` and root', () => { + set.config('latex.outDir', './output') set.root(fixture, 'main.tex') assert.pathStrictEqual(lw.file.getOutDir(), 'output') }) - it('should get output directory with relative `latex.outDir`, root, and an input latex', async () => { + it('should get output directory with relative `latex.outDir`, root, and an input latex', () => { const texPath = get.path(fixture, 'main.tex') - await set.config('latex.outDir', 'output') + set.config('latex.outDir', 'output') set.root(fixture, 'main.tex') assert.pathStrictEqual(lw.file.getOutDir(texPath), 'output') }) - it('should get output directory with placeholder in `latex.outDir` and root', async () => { - await set.config('latex.outDir', '%DIR%') + it('should get output directory with placeholder in `latex.outDir` and root', () => { + set.config('latex.outDir', '%DIR%') set.root(fixture, 'main.tex') assert.pathStrictEqual(lw.file.getOutDir(), lw.root.dir.path) }) - it('should get output directory with placeholder in `latex.outDir`, root, and an input latex', async () => { + it('should get output directory with placeholder in `latex.outDir`, root, and an input latex', () => { const rootDir = get.path(fixture) const texPath = get.path(fixture, 'main.tex') - await set.config('latex.outDir', '%DIR%') + set.config('latex.outDir', '%DIR%') set.root(fixture, 'main.tex') assert.pathStrictEqual(lw.file.getOutDir(texPath), rootDir) }) - it('should get output directory from last compilation if `latex.outDir` is `%DIR%`', async () => { - await set.config('latex.outDir', '%DIR%') + it('should get output directory from last compilation if `latex.outDir` is `%DIR%`', () => { + set.config('latex.outDir', '%DIR%') set.root(fixture, 'main.tex') lw.file.setTeXDirs(lw.root.file.path ?? '', '/output') assert.pathStrictEqual(lw.file.getOutDir(), '/output') }) - it('should ignore output directory from last compilation if `latex.outDir` is not `%DIR%`', async () => { - await set.config('latex.outDir', '/output') + it('should ignore output directory from last compilation if `latex.outDir` is not `%DIR%`', () => { + set.config('latex.outDir', '/output') set.root(fixture, 'main.tex') lw.file.setTeXDirs(lw.root.file.path ?? '', '/trap') assert.pathStrictEqual(lw.file.getOutDir(), '/output') }) - it('should ignore output directory from last compilation if no `outdir` is recorded', async () => { - await set.config('latex.outDir', '%DIR%') + it('should ignore output directory from last compilation if no `outdir` is recorded', () => { + set.config('latex.outDir', '%DIR%') set.root(fixture, 'main.tex') lw.file.setTeXDirs(lw.root.file.path ?? '') assert.pathStrictEqual(lw.file.getOutDir(), lw.root.dir.path) }) - it('should handle empty `latex.outDir` correctly', async () => { - await set.config('latex.outDir', '') + it('should handle empty `latex.outDir` correctly', () => { + set.config('latex.outDir', '') set.root(fixture, 'main.tex') assert.pathStrictEqual(lw.file.getOutDir(), './') }) - it('should handle absolute `latex.outDir` with trailing slashes correctly', async () => { - await set.config('latex.outDir', '/output/') + it('should handle absolute `latex.outDir` with trailing slashes correctly', () => { + set.config('latex.outDir', '/output/') set.root(fixture, 'main.tex') assert.pathStrictEqual(lw.file.getOutDir(), '/output') }) - it('should handle relative `latex.outDir` with trailing slashes correctly', async () => { - await set.config('latex.outDir', 'output/') + it('should handle relative `latex.outDir` with trailing slashes correctly', () => { + set.config('latex.outDir', 'output/') set.root(fixture, 'main.tex') assert.pathStrictEqual(lw.file.getOutDir(), 'output') }) @@ -184,7 +184,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { const texPath = get.path(fixture, 'main.tex') const flsPath = get.path(fixture, 'output', 'main.fls') - await set.config('latex.outDir', 'output') + set.config('latex.outDir', 'output') assert.pathStrictEqual(await lw.file.getFlsPath(texPath), flsPath) }) @@ -233,18 +233,18 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { ]) }) - it('should correctly find BibTeX files in `latex.bibDirs`', async () => { + it('should correctly find BibTeX files in `latex.bibDirs`', () => { set.root(fixture, 'main.tex') - await set.config('latex.bibDirs', [ path.resolve(lw.root.dir.path ?? '', 'subdir') ]) + set.config('latex.bibDirs', [ path.resolve(lw.root.dir.path ?? '', 'subdir') ]) const result = lw.file.getBibPath('sub.bib', lw.root.dir.path ?? '') assert.listStrictEqual(result, [ path.resolve(lw.root.dir.path ?? '', 'subdir', 'sub.bib') ]) }) - it('should return an empty array when no BibTeX file is found', async () => { + it('should return an empty array when no BibTeX file is found', () => { set.root(fixture, 'main.tex') - await set.config('latex.bibDirs', [ path.resolve(lw.root.dir.path ?? '', 'subdir') ]) + set.config('latex.bibDirs', [ path.resolve(lw.root.dir.path ?? '', 'subdir') ]) const result = lw.file.getBibPath('nonexistent.bib', path.resolve(lw.root.dir.path ?? '', 'output')) assert.listStrictEqual(result, [ ]) }) @@ -258,29 +258,29 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { ]) }) - it('should handle case when kpsewhich is disabled and BibTeX file not found', async () => { + it('should handle case when kpsewhich is disabled and BibTeX file not found', () => { const stub = sinon.stub(lw.external, 'sync').returns({ pid: 0, status: 0, stdout: get.path(fixture, 'nonexistent.bib'), output: [''], stderr: '', signal: 'SIGTERM' }) - await set.config('kpsewhich.bibtex.enabled', false) + set.config('kpsewhich.bibtex.enabled', false) set.root(fixture, 'main.tex') const result = lw.file.getBibPath('nonexistent.bib', lw.root.dir.path ?? '') stub.restore() assert.listStrictEqual(result, [ ]) }) - it('should handle case when kpsewhich is enabled and BibTeX file not found', async () => { + it('should handle case when kpsewhich is enabled and BibTeX file not found', () => { const nonPath = get.path(fixture, 'nonexistent.bib') const stub = sinon.stub(lw.external, 'sync').returns({ pid: 0, status: 0, stdout: get.path(fixture, 'nonexistent.bib'), output: [''], stderr: '', signal: 'SIGTERM' }) - await set.config('kpsewhich.bibtex.enabled', true) + set.config('kpsewhich.bibtex.enabled', true) set.root(fixture, 'main.tex') const result = lw.file.getBibPath('nonexistent.bib', lw.root.dir.path ?? '') stub.restore() assert.listStrictEqual(result, [ nonPath ]) }) - it('should return an empty array when kpsewhich is enabled but file is not found', async () => { + it('should return an empty array when kpsewhich is enabled but file is not found', () => { const stub = sinon.stub(lw.external, 'sync').returns({ pid: 0, status: 0, stdout: '', output: [''], stderr: '', signal: 'SIGTERM' }) - await set.config('kpsewhich.bibtex.enabled', true) + set.config('kpsewhich.bibtex.enabled', true) set.root(fixture, 'main.tex') const result = lw.file.getBibPath('another-nonexistent.bib', lw.root.dir.path ?? '') stub.restore() @@ -330,40 +330,40 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) describe('lw.file.getJobname', () => { - it('should return the jobname if present in configuration', async () => { + it('should return the jobname if present in configuration', () => { const texPath = get.path(fixture, 'main.tex') - await set.config('latex.jobname', 'myJob') + set.config('latex.jobname', 'myJob') assert.strictEqual(lw.file.getJobname(texPath), 'myJob') }) - it('should return the name of the input texPath if jobname is empty', async () => { + it('should return the name of the input texPath if jobname is empty', () => { const texPath = get.path(fixture, 'main.tex') - await set.config('latex.jobname', '') + set.config('latex.jobname', '') const expectedJobname = path.parse(texPath).name assert.strictEqual(lw.file.getJobname(texPath), expectedJobname) }) - it('should return the name of the input texPath if configuration is not set', async () => { + it('should return the name of the input texPath if configuration is not set', () => { const texPath = get.path(fixture, 'main.tex') - await set.config('latex.jobname', undefined) // Ensuring the jobname is not set + set.config('latex.jobname', undefined) // Ensuring the jobname is not set const expectedJobname = path.parse(texPath).name assert.strictEqual(lw.file.getJobname(texPath), expectedJobname) }) }) describe('lw.file.getPdfPath', () => { - it('should return the correct PDF path when outDir is empty', async () => { - await set.config('latex.outDir', '') + it('should return the correct PDF path when outDir is empty', () => { + set.config('latex.outDir', '') set.root(fixture, 'main.tex') const texpath = lw.root.file.path ?? '' assert.pathStrictEqual(lw.file.getPdfPath(texpath), texpath.replaceAll('.tex', '.pdf')) }) - it('should return the correct PDF path when outDir is specified', async () => { - await set.config('latex.outDir', 'output') + it('should return the correct PDF path when outDir is specified', () => { + set.config('latex.outDir', 'output') set.root(fixture, 'main.tex') const texpath = lw.root.file.path ?? '' assert.pathStrictEqual(lw.file.getPdfPath(texpath), texpath.replaceAll('main.tex', 'output/main.pdf')) @@ -503,16 +503,16 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) describe('kpsewhich', () => { - it('should call kpsewhich with correct arguments', async () => { - await set.config('kpsewhich.path', 'kpse') + it('should call kpsewhich with correct arguments', () => { + set.config('kpsewhich.path', 'kpse') const stub = sinon.stub(lw.external, 'sync').returns({ pid: 0, status: 0, stdout: '', output: [''], stderr: '', signal: 'SIGTERM' }) lw.file.kpsewhich('article.cls') stub.restore() sinon.assert.calledWith(stub, 'kpse', ['article.cls'], sinon.match.any) }) - it('should handle isBib flag correctly', async () => { - await set.config('kpsewhich.path', 'kpse') + it('should handle isBib flag correctly', () => { + set.config('kpsewhich.path', 'kpse') const stub = sinon.stub(lw.external, 'sync').returns({ pid: 0, status: 0, stdout: '', output: [''], stderr: '', signal: 'SIGTERM' }) lw.file.kpsewhich('reference.bib', true) stub.restore() diff --git a/test/units/02_core_watcher.test.ts b/test/units/02_core_watcher.test.ts index c3c9a0c9e..2d4059aa7 100644 --- a/test/units/02_core_watcher.test.ts +++ b/test/units/02_core_watcher.test.ts @@ -18,7 +18,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { const getOnDeleteHandlers = () => _onDeleteHandlersSpy.call(lw.watcher.src) as Set<(uri: vscode.Uri) => void> before(() => { - mock.object(lw, 'file', 'watcher') + mock.init(lw, 'file', 'watcher') _onDidChangeSpy = sinon.spy(lw.watcher.src as any, 'onDidChange') _onDidDeleteSpy = sinon.spy(lw.watcher.src as any, 'onDidDelete') _watchersSpy = sinon.spy(lw.watcher.src as any, 'watchers', ['get']).get @@ -210,10 +210,10 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { const stub = sinon.stub() const handler = (filePath: vscode.Uri) => { stub(filePath.fsPath) } - beforeEach(async () => { + beforeEach(() => { stub.reset() lw.watcher.src.onDelete(handler) - await set.config('latex.watch.delay', 100) + set.config('latex.watch.delay', 100) }) afterEach(() => { diff --git a/test/units/03_core_cache.test.ts b/test/units/03_core_cache.test.ts index cf908a2d0..c82e92862 100644 --- a/test/units/03_core_cache.test.ts +++ b/test/units/03_core_cache.test.ts @@ -9,7 +9,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { const fixture = path.basename(__filename).split('.')[0] before(() => { - mock.object(lw, 'file', 'watcher', 'cache') + mock.init(lw, 'file', 'watcher', 'cache') }) after(() => { @@ -38,7 +38,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should excluded files with config set ', async () => { - await set.config('latex.watch.files.ignore', ['**/*.bbl']) + set.config('latex.watch.files.ignore', ['**/*.bbl']) log.start() await lw.cache.refreshCache(bblPath) @@ -53,8 +53,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) describe('lw.cache.canCache', () => { - beforeEach(async () => { - await set.config('latex.watch.files.ignore', []) + beforeEach(() => { + set.config('latex.watch.files.ignore', []) }) it('should cache supported TeX files', async () => { @@ -284,9 +284,9 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) describe('lw.cache.refreshCacheAggressive', () => { - beforeEach(async () => { - await set.config('intellisense.update.aggressive.enabled', true) - await set.config('intellisense.update.delay', 100) + beforeEach(() => { + set.config('intellisense.update.aggressive.enabled', true) + set.config('intellisense.update.delay', 100) }) it('should not aggressively cache non-cached files', async function (this: Mocha.Context) { @@ -335,7 +335,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { this.slow(350) const texPath = get.path(fixture, 'main.tex') - await set.config('intellisense.update.aggressive.enabled', false) + set.config('intellisense.update.aggressive.enabled', false) lw.cache.add(texPath) await lw.cache.refreshCache(texPath) const stub = mock.textDocument(texPath, '', { isDirty: true }) @@ -550,7 +550,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { it('should add a child if it is defined in `latex.texDirs`', async () => { const texPath = get.path(fixture, 'main.tex') - await set.config('latex.texDirs', [ get.path(fixture, 'update_children_xr', 'sub') ]) + set.config('latex.texDirs', [ get.path(fixture, 'update_children_xr', 'sub') ]) set.root(texPath) lw.cache.add(texPath) @@ -775,7 +775,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should not add \\bibdata if the bib is excluded', async () => { - await set.config('latex.watch.files.ignore', ['**/main.bib']) + set.config('latex.watch.files.ignore', ['**/main.bib']) const toParse = get.path(fixture, 'load_aux_file', 'main.tex') set.root(fixture, 'load_aux_file', 'main.tex') await lw.cache.refreshCache(toParse) diff --git a/test/units/04_core_root.test.ts b/test/units/04_core_root.test.ts index 3abf24640..445ccbded 100644 --- a/test/units/04_core_root.test.ts +++ b/test/units/04_core_root.test.ts @@ -8,7 +8,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { const fixture = path.basename(__filename).split('.')[0] before(() => { - mock.object(lw, 'file', 'watcher', 'cache', 'root') + mock.init(lw, 'file', 'watcher', 'cache', 'root') }) after(() => { @@ -16,8 +16,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) describe('on root file deletion', () => { - beforeEach(async () => { - await set.config('latex.watch.delay', 100) + beforeEach(() => { + set.config('latex.watch.delay', 100) }) afterEach(() => { @@ -271,8 +271,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) describe('lw.root.findFromActive', () => { - beforeEach(async () => { - await set.config('latex.rootFile.indicator', '\\documentclass[]{}') + beforeEach(() => { + set.config('latex.rootFile.indicator', '\\documentclass[]{}') }) it('should do nothing if there is no active editor', async () => { @@ -341,7 +341,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { describe('lw.root.getIndicator', () => { it('should use \\begin{document} indicator on selecting `\\begin{document}`', async () => { - await set.config('latex.rootFile.indicator', '\\begin{document}') + set.config('latex.rootFile.indicator', '\\begin{document}') const texPath = get.path(fixture, 'main.tex') @@ -354,7 +354,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should return \\documentclass indicator on other values', async () => { - await set.config('latex.rootFile.indicator', 'invalid value') + set.config('latex.rootFile.indicator', 'invalid value') const texPath = get.path(fixture, 'main.tex') @@ -368,19 +368,19 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) describe('lw.root.findInWorkspace', () => { - beforeEach(async () => { - await set.config('latex.rootFile.indicator', '\\begin{document}') // avoid active editor check + beforeEach(() => { + set.config('latex.rootFile.indicator', '\\begin{document}') // avoid active editor check }) it('should follow `latex.search.rootFiles.include` config', async () => { - await set.config('latex.search.rootFiles.include', [ 'absolutely-nothing.tex' ]) + set.config('latex.search.rootFiles.include', [ 'absolutely-nothing.tex' ]) await lw.root.find() assert.strictEqual(lw.root.file.path, undefined) }) it('should follow `latex.search.rootFiles.exclude` config', async () => { - await set.config('latex.search.rootFiles.exclude', [ '**/*' ]) + set.config('latex.search.rootFiles.exclude', [ '**/*' ]) await lw.root.find() assert.strictEqual(lw.root.file.path, undefined) @@ -389,8 +389,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { it('should find the correct root from workspace', async () => { const texPath = get.path(fixture, 'find_workspace', 'main.tex') - await set.config('latex.search.rootFiles.include', [ `${fixture}/find_workspace/**/*.tex` ]) - await set.config('latex.search.rootFiles.exclude', [ `${fixture}/find_workspace/**/parent.tex` ]) + set.config('latex.search.rootFiles.include', [ `${fixture}/find_workspace/**/*.tex` ]) + set.config('latex.search.rootFiles.exclude', [ `${fixture}/find_workspace/**/parent.tex` ]) await lw.root.find() assert.hasLog('Try finding root from current workspaceRootDir:') @@ -398,7 +398,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should ignore root file indicators in comments', async () => { - await set.config('latex.search.rootFiles.include', [ `${fixture}/find_workspace/**/comment.tex` ]) + set.config('latex.search.rootFiles.include', [ `${fixture}/find_workspace/**/comment.tex` ]) await lw.root.find() assert.strictEqual(lw.root.file.path, undefined) @@ -408,7 +408,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { const texPath = get.path(fixture, 'find_workspace', 'main.tex') const texPathAnother = get.path(fixture, 'find_workspace', 'another.tex') - await set.config('latex.search.rootFiles.include', [ `${fixture}/find_workspace/**/*.tex` ]) + set.config('latex.search.rootFiles.include', [ `${fixture}/find_workspace/**/*.tex` ]) const stub = mock.activeTextEditor(texPathAnother, '\\documentclass{article}\n') await lw.root.find() stub.restore() @@ -421,8 +421,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { const texPath = get.path(fixture, 'find_workspace', 'parent.tex') const texPathAnother = get.path(fixture, 'find_workspace', 'another.tex') - await set.config('latex.search.rootFiles.include', [ `${fixture}/find_workspace/**/*.tex` ]) - await set.config('latex.search.rootFiles.exclude', [ `${fixture}/find_workspace/main.tex` ]) + set.config('latex.search.rootFiles.include', [ `${fixture}/find_workspace/**/*.tex` ]) + set.config('latex.search.rootFiles.exclude', [ `${fixture}/find_workspace/main.tex` ]) await lw.cache.refreshCache(texPath) const stub = mock.activeTextEditor(texPathAnother, '\\documentclass{article}\n') await lw.root.find() @@ -436,7 +436,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { const texPath = get.path(fixture, 'find_workspace', 'parent.tex') const texPathAnother = get.path(fixture, 'find_workspace', 'another.tex') - await set.config('latex.search.rootFiles.include', [ `${fixture}/find_workspace/**/*.tex` ]) + set.config('latex.search.rootFiles.include', [ `${fixture}/find_workspace/**/*.tex` ]) await lw.cache.refreshCache(texPath) const stub = mock.activeTextEditor(texPathAnother, '\\documentclass{article}\n') await lw.root.find() @@ -449,7 +449,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { it('should find the correct root if current root is in the candidates', async () => { const texPath = get.path(fixture, 'find_workspace', 'main.tex') - await set.config('latex.search.rootFiles.include', [ `${fixture}/find_workspace/**/*.tex` ]) + set.config('latex.search.rootFiles.include', [ `${fixture}/find_workspace/**/*.tex` ]) set.root(fixture, 'find_workspace', 'main.tex') const stub = mock.activeTextEditor(texPath, '\\documentclass{article}\n') await lw.root.find() @@ -468,7 +468,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should not change root if no new root can be found, only refresh outline', async () => { - await set.config('latex.search.rootFiles.exclude', [ '**/*.*' ]) + set.config('latex.search.rootFiles.exclude', [ '**/*.*' ]) await lw.root.find() diff --git a/test/units/05_compile_queue.test.ts b/test/units/05_compile_queue.test.ts index 7548f962f..37dda6af3 100644 --- a/test/units/05_compile_queue.test.ts +++ b/test/units/05_compile_queue.test.ts @@ -6,7 +6,7 @@ import { queue } from '../../src/compile/queue' describe(path.basename(__filename).split('.')[0] + ':', () => { before(() => { - mock.object(lw, 'file', 'root') + mock.init(lw, 'file', 'root') }) after(() => { diff --git a/test/units/06_compile_recipe.test.ts b/test/units/06_compile_recipe.test.ts index 0cd4437ce..96e36dad9 100644 --- a/test/units/06_compile_recipe.test.ts +++ b/test/units/06_compile_recipe.test.ts @@ -12,16 +12,16 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { let mkdirStub: sinon.SinonStub before(() => { - mock.object(lw, 'file', 'root') + mock.init(lw, 'file', 'root') getOutDirStub = sinon.stub(lw.file, 'getOutDir').returns('.') getIncludedTeXStub = lw.cache.getIncludedTeX as sinon.SinonStub mkdirStub = sinon.stub(lw.external, 'mkdirSync').returns(undefined) }) - beforeEach(async () => { + beforeEach(() => { initialize() getIncludedTeXStub.returns([]) - await set.config('latex.recipe.default', 'first') + set.config('latex.recipe.default', 'first') }) afterEach(() => { @@ -41,7 +41,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { this.slow(500) const expectedImageName = 'your-docker-image' - await set.config('docker.image.latex', expectedImageName) + await set.codeConfig('docker.image.latex', expectedImageName) await sleep(150) assert.strictEqual(process.env['LATEXWORKSHOP_DOCKER_LATEX'], expectedImageName) @@ -51,7 +51,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { this.slow(500) const expectedDockerPath = '/usr/local/bin/docker' - await set.config('docker.path', expectedDockerPath) + await set.codeConfig('docker.path', expectedDockerPath) await sleep(150) assert.strictEqual(process.env['LATEXWORKSHOP_DOCKER_PATH'], expectedDockerPath) @@ -72,8 +72,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { it('should call `createOutputSubFolders` with correct args', async () => { const rootFile = set.root('main.tex') const subPath = get.path('sub', 'main.tex') - await set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk' }]) - await set.config('latex.recipes', [{ name: 'Recipe1', tools: ['latexmk'] }]) + set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk' }]) + set.config('latex.recipes', [{ name: 'Recipe1', tools: ['latexmk'] }]) lw.root.subfiles.path = subPath getIncludedTeXStub.returns([rootFile, subPath]) @@ -84,8 +84,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { it('should call `createOutputSubFolders` with correct args with subfiles package', async () => { const rootFile = set.root('main.tex') const subPath = get.path('sub', 'main.tex') - await set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk' }]) - await set.config('latex.recipes', [{ name: 'Recipe1', tools: ['latexmk'] }]) + set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk' }]) + set.config('latex.recipes', [{ name: 'Recipe1', tools: ['latexmk'] }]) lw.root.subfiles.path = subPath getIncludedTeXStub.returns([rootFile, subPath]) @@ -95,8 +95,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { it('should not call buildLoop if no tool is created', async () => { const rootFile = set.root('main.tex') - await set.config('latex.tools', []) - await set.config('latex.recipes', [{ name: 'Recipe1', tools: ['nonexistentTool'] }]) + set.config('latex.tools', []) + set.config('latex.recipes', [{ name: 'Recipe1', tools: ['nonexistentTool'] }]) const stub = sinon.stub() await build(rootFile, 'latex', stub) @@ -106,8 +106,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { it('should set lw.compile.compiledPDFPath', async () => { const rootFile = set.root('main.tex') - await set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk' }]) - await set.config('latex.recipes', [{ name: 'Recipe1', tools: ['latexmk'] }]) + set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk' }]) + set.config('latex.recipes', [{ name: 'Recipe1', tools: ['latexmk'] }]) await build(rootFile, 'latex', async () => {}) @@ -128,7 +128,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { it('should do nothing but log an error if no recipe is found', async () => { const rootFile = set.root('main.tex') - await set.config('latex.recipes', []) + set.config('latex.recipes', []) await build(rootFile, 'latex', async () => {}) @@ -138,9 +138,9 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { it('should create build tools based on magic comments when enabled', async () => { const rootFile = set.root('magic.tex') readStub.resolves('% !TEX program = pdflatex\n') - await set.config('latex.recipes', []) - await set.config('latex.build.forceRecipeUsage', false) - await set.config('latex.magic.args', ['--shell-escape']) + set.config('latex.recipes', []) + set.config('latex.build.forceRecipeUsage', false) + set.config('latex.magic.args', ['--shell-escape']) await build(rootFile, 'latex', async () => {}) @@ -153,8 +153,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { it('should do nothing but log an error with magic comments but disabled', async () => { const rootFile = set.root('magic.tex') - await set.config('latex.recipes', []) - await set.config('latex.build.forceRecipeUsage', true) + set.config('latex.recipes', []) + set.config('latex.build.forceRecipeUsage', true) await build(rootFile, 'latex', async () => {}) @@ -163,8 +163,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { it('should skip undefined tools in the recipe and log an error', async () => { const rootFile = set.root('main.tex') - await set.config('latex.tools', [{ name: 'existingTool', command: 'pdflatex' }]) - await set.config('latex.recipes', [{ name: 'Recipe1', tools: ['nonexistentTool', 'existingTool'] }]) + set.config('latex.tools', [{ name: 'existingTool', command: 'pdflatex' }]) + set.config('latex.recipes', [{ name: 'Recipe1', tools: ['nonexistentTool', 'existingTool'] }]) await build(rootFile, 'latex', async () => {}) @@ -178,8 +178,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { it('should do nothing but log an error if no tools are prepared', async () => { const rootFile = set.root('main.tex') - await set.config('latex.tools', []) - await set.config('latex.recipes', [{ name: 'Recipe1', tools: ['nonexistentTool'] }]) + set.config('latex.tools', []) + set.config('latex.recipes', [{ name: 'Recipe1', tools: ['nonexistentTool'] }]) await build(rootFile, 'latex', async () => {}) @@ -256,8 +256,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { queue.clear() }) - beforeEach(async () => { - await set.config('latex.build.forceRecipeUsage', false) + beforeEach(() => { + set.config('latex.build.forceRecipeUsage', false) }) afterEach(() => { @@ -334,8 +334,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should detect only LW recipe comment', async () => { - await set.config('latex.tools', [{ name: 'Tool1', command: 'pdflatex' }, { name: 'Tool2', command: 'xelatex' }]) - await set.config('latex.recipes', [{ name: 'Recipe1', tools: ['Tool1'] }, { name: 'Recipe2', tools: ['Tool2'] }]) + set.config('latex.tools', [{ name: 'Tool1', command: 'pdflatex' }, { name: 'Tool2', command: 'xelatex' }]) + set.config('latex.recipes', [{ name: 'Recipe1', tools: ['Tool1'] }, { name: 'Recipe2', tools: ['Tool2'] }]) readStub.resolves('% !LW recipe = Recipe2\n') @@ -404,10 +404,10 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { queue.clear() }) - beforeEach(async () => { - await set.config('latex.build.forceRecipeUsage', false) - await set.config('latex.magic.args', ['--shell-escape']) - await set.config('latex.magic.bib.args', ['--min-crossrefs=1000']) + beforeEach(() => { + set.config('latex.build.forceRecipeUsage', false) + set.config('latex.magic.args', ['--shell-escape']) + set.config('latex.magic.bib.args', ['--min-crossrefs=1000']) }) afterEach(() => { @@ -481,13 +481,13 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) describe('lw.compile->recipe.findRecipe', () => { - beforeEach(async () => { - await set.config('latex.tools', [{ name: 'Tool1', command: 'pdflatex' }, { name: 'Tool2', command: 'xelatex' }, { name: 'Tool3', command: 'lualatex' }]) - await set.config('latex.recipes', [{ name: 'Recipe1', tools: ['Tool1'] }, { name: 'Recipe2', tools: ['Tool2'] }, { name: 'Recipe3', tools: ['Tool3'] }]) + beforeEach(() => { + set.config('latex.tools', [{ name: 'Tool1', command: 'pdflatex' }, { name: 'Tool2', command: 'xelatex' }, { name: 'Tool3', command: 'lualatex' }]) + set.config('latex.recipes', [{ name: 'Recipe1', tools: ['Tool1'] }, { name: 'Recipe2', tools: ['Tool2'] }, { name: 'Recipe3', tools: ['Tool3'] }]) }) it('should do nothing but log an error if no recipes are defined', async () => { - await set.config('latex.recipes', []) + set.config('latex.recipes', []) await build('dummy.tex', 'latex', async () => {}) @@ -495,7 +495,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should use the default recipe name if recipeName is undefined', async () => { - await set.config('latex.recipe.default', 'Recipe2') + set.config('latex.recipe.default', 'Recipe2') await build('dummy.tex', 'latex', async () => {}) @@ -511,7 +511,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should return the last used recipe if defaultRecipeName is `lastUsed`', async () => { - await set.config('latex.recipe.default', 'lastUsed') + set.config('latex.recipe.default', 'lastUsed') await build('dummy.tex', 'latex', async () => {}, 'Recipe2') queue.clear() @@ -522,8 +522,22 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { assert.strictEqual(step.name, 'Tool2') }) + it('should use the updated new tools in the last used recipe if defaultRecipeName is `lastUsed`', async () => { + set.config('latex.recipe.default', 'lastUsed') + + await build('dummy.tex', 'latex', async () => {}, 'Recipe2') + queue.clear() + + set.config('latex.recipes', [{ name: 'Recipe1', tools: ['Tool1'] }, { name: 'Recipe2', tools: ['Tool3'] }, { name: 'Recipe3', tools: ['Tool3'] }]) + await build('dummy.tex', 'latex', async () => {}) + + const step = queue.getStep() + assert.ok(step) + assert.strictEqual(step.name, 'Tool3') + }) + it('should reset prevRecipe if the language ID changes', async () => { - await set.config('latex.recipe.default', 'lastUsed') + set.config('latex.recipe.default', 'lastUsed') await build('dummy.tex', 'latex', async () => {}, 'Recipe2') queue.clear() @@ -535,7 +549,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should return the first matching recipe based on langId if no recipe is found', async () => { - await set.config('latex.recipes', [ + set.config('latex.recipes', [ { name: 'recipe1', tools: [] }, { name: 'rsweave Recipe', tools: [] }, { name: 'weave.jl Recipe', tools: [] }, @@ -599,9 +613,9 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { extRoot = lw.extensionRoot }) - beforeEach(async () => { - await set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk' }]) - await set.config('latex.recipes', [{ name: 'Recipe1', tools: ['latexmk'] }]) + beforeEach(() => { + set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk' }]) + set.config('latex.recipes', [{ name: 'Recipe1', tools: ['latexmk'] }]) }) afterEach(() => { @@ -620,7 +634,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should modify command when Docker is enabled on Windows', async () => { - await set.config('docker.enabled', true) + set.config('docker.enabled', true) setPlatform('win32') lw.extensionRoot = '/path/to/extension' @@ -632,7 +646,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should modify command and chmod when Docker is enabled on non-Windows', async () => { - await set.config('docker.enabled', true) + set.config('docker.enabled', true) setPlatform('linux') lw.extensionRoot = '/path/to/extension' @@ -647,7 +661,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should not modify command when Docker is disabled', async () => { - await set.config('docker.enabled', false) + set.config('docker.enabled', false) await build('dummy.tex', 'latex', async () => {}) @@ -657,7 +671,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should replace argument placeholders', async () => { - await set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk', args: ['%DOC%', '%DOC%', '%DIR%'], env: {} }]) + set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk', args: ['%DOC%', '%DOC%', '%DIR%'], env: {} }]) const rootFile = set.root('main.tex') await build(rootFile, 'latex', async () => {}) @@ -670,7 +684,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should set TeX directories correctly', async () => { - await set.config('latex.tools', [ + set.config('latex.tools', [ { name: 'latexmk', command: 'latexmk', @@ -688,7 +702,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should process environment variables correctly', async () => { - await set.config('latex.tools', [ + set.config('latex.tools', [ { name: 'latexmk', command: 'latexmk', @@ -706,8 +720,8 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { }) it('should append max print line arguments when enabled', async () => { - await set.config('latex.option.maxPrintLine.enabled', true) - await set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk' }]) + set.config('latex.option.maxPrintLine.enabled', true) + set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk' }]) syncStub.returns({ stdout: 'pdfTeX 3.14159265-2.6-1.40.21 (MiKTeX 2.9.7350 64-bit)' }) const rootFile = set.root('main.tex') @@ -717,7 +731,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { assert.ok(step) assert.ok(step.args?.includes('--max-print-line=' + lw.constant.MAX_PRINT_LINE), step.args?.join(' ')) - await set.config('latex.tools', [{ name: 'latexmk', command: 'pdflatex' }]) + set.config('latex.tools', [{ name: 'latexmk', command: 'pdflatex' }]) initialize() await build(rootFile, 'latex', async () => {}) @@ -725,7 +739,7 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { assert.ok(step) assert.ok(step.args?.includes('--max-print-line=' + lw.constant.MAX_PRINT_LINE), step.args?.join(' ')) - await set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk', args: ['--lualatex'] }]) + set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk', args: ['--lualatex'] }]) initialize() await build(rootFile, 'latex', async () => {}) @@ -742,9 +756,9 @@ describe(path.basename(__filename).split('.')[0] + ':', () => { syncStub = sinon.stub(lw.external, 'sync') }) - beforeEach(async () => { - await set.config('latex.option.maxPrintLine.enabled', true) - await set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk' }]) + beforeEach(() => { + set.config('latex.option.maxPrintLine.enabled', true) + set.config('latex.tools', [{ name: 'latexmk', command: 'latexmk' }]) }) afterEach(() => { diff --git a/test/units/07_compile_external.test.ts b/test/units/07_compile_external.test.ts index cfe83f971..c1aab1ab2 100644 --- a/test/units/07_compile_external.test.ts +++ b/test/units/07_compile_external.test.ts @@ -10,7 +10,7 @@ import type { ExternalStep } from '../../src/types' describe(path.basename(__filename).split('.')[0] + ':', () => { before(() => { - mock.object(lw, 'file', 'root') + mock.init(lw, 'file', 'root') }) after(() => { diff --git a/test/units/08_compile_build.test.ts b/test/units/08_compile_build.test.ts index 6f4e0f2ba..0e9235a41 100644 --- a/test/units/08_compile_build.test.ts +++ b/test/units/08_compile_build.test.ts @@ -1,3 +1,4 @@ +import * as vscode from 'vscode' import * as path from 'path' import * as sinon from 'sinon' import { assert, get, mock, set } from './utils' @@ -11,19 +12,22 @@ describe.only(path.basename(__filename).split('.')[0] + ':', () => { let findStub: sinon.SinonStub before(() => { - mock.object(lw, 'file', 'root') - ;(lw.cache.getIncludedTeX as sinon.SinonStub).returns([ get.path('main.tex') ]) + mock.init(lw, 'file', 'root') + ;(lw.cache.getIncludedTeX as sinon.SinonStub).returns([get.path('main.tex')]) findStub = sinon.stub(lw.root, 'find') }) - beforeEach(async () => { + beforeEach(() => { activeStub = mock.activeTextEditor(get.path('main.tex'), '', { languageId: 'latex' }) findStub.callsFake(() => { set.root('main.tex') return Promise.resolve(undefined) }) - await set.config('latex.tools', [{ name: 'tool', command: 'bash', args: ['-c', 'exit 0;'] }]) - await set.config('latex.recipes', [{ name: 'recipe', tools: ['tool'] }]) + set.config('latex.tools', [ + { name: 'tool', command: 'bash', args: ['-c', 'exit 0;'] }, + { name: 'bad', command: 'bash', args: ['-c', 'exit 1;'] }, + ]) + set.config('latex.recipes', [{ name: 'recipe', tools: ['tool'] }]) }) afterEach(() => { @@ -65,21 +69,24 @@ describe.only(path.basename(__filename).split('.')[0] + ':', () => { }) it('should use external command to build project if set', async () => { - await set.config('latex.external.build.command', 'bash') - await set.config('latex.external.build.args', ['-c', 'exit 0;#external']) + set.config('latex.external.build.command', 'bash') + set.config('latex.external.build.args', ['-c', 'exit 0;#external']) await build() assert.hasLog('Recipe step 1 The command is bash:["-c","exit 0;#external"].') }) - it.only('should use the current pwd as external command cwd', async () => { - await set.config('latex.external.build.command', 'bash') - await set.config('latex.external.build.args', ['-c', 'echo $PWD']) + it('should use the current pwd as external command cwd', async () => { + set.config('latex.external.build.command', 'bash') + set.config('latex.external.build.args', ['-c', 'echo $PWD']) await build() - assert.pathStrictEqual(lwLog.getCachedLog().CACHED_COMPILER[0].trim(), path.dirname(get.path('main.tex')).replace(/^([a-zA-Z]):/, (_, p1: string) => '\\' + p1.toLowerCase())) + assert.pathStrictEqual( + lwLog.getCachedLog().CACHED_COMPILER[0].trim(), + path.dirname(get.path('main.tex')).replace(/^([a-zA-Z]):/, (_, p1: string) => '\\' + p1.toLowerCase()) + ) }) it('should do nothing if cannot find root and not external', async () => { @@ -122,4 +129,69 @@ describe.only(path.basename(__filename).split('.')[0] + ':', () => { assert.hasLog(`Building root file: ${get.path('main.tex')}`) }) }) + + describe('lw.compile->build.buildLoop', () => { + it('should not loop a new build if another one is ongoing', async () => { + set.config('latex.tools', [{ name: 'tool', command: 'bash', args: ['-c', 'sleep .5;exit 0;'] }]) + + const buildPromise = build() + await build() + await buildPromise + + assert.hasLog('Another build loop is already running.') + }) + + it('should increment `lw.compile.compiledPDFWriting` to avoid PDF refresh during compilation', async () => { + await build() + + assert.ok(lw.compile.compiledPDFWriting > 0, lw.compile.compiledPDFWriting.toString()) + + await new Promise((resolve) => + setTimeout( + resolve, + (vscode.workspace.getConfiguration('latex-workshop').get('latex.watch.pdf.delay') as number) + 100 + ) + ) + + assert.strictEqual(lw.compile.compiledPDFWriting, 0) + }) + + it('should handle multiple steps one by one', async () => { + set.config('latex.recipes', [{ name: 'recipe', tools: ['tool', 'tool'] }]) + + await build() + + assert.hasLog('Recipe step 1 The command is bash:["-c","exit 0;"].') + assert.hasLog('Recipe step 2 The command is bash:["-c","exit 0;"].') + }) + + it('should early-terminate if a step returns non-zero code', async () => { + set.config('latex.recipes', [{ name: 'recipe', tools: ['bad', 'tool'] }]) + set.config('latex.autoBuild.cleanAndRetry.enabled', false) + + await build() + + assert.hasLog('Recipe step 1 The command is bash:["-c","exit 1;"].') + assert.notHasLog('Recipe step 2 The command is bash:["-c","exit 0;"].') + }) + + it('should correctly set `skipped` flag to `true` for skipped latexmk steps', async () => { + set.config('latex.tools', [ + { name: 'tool', command: 'bash', args: ['-c', 'echo "Latexmk: All targets (build) are up-to-date";'] }, + ]) + + const refreshStub = lw.viewer.refresh as sinon.SinonStub + refreshStub.resetHistory() + await build() + + assert.ok(!refreshStub.called) + + set.config('latex.tools', [{ name: 'tool', command: 'bash', args: ['-c', 'exit 0;'] }]) + + refreshStub.resetHistory() + await build() + + assert.ok(refreshStub.called) + }) + }) }) diff --git a/test/units/utils.ts b/test/units/utils.ts index 4ddbd2733..9733078bd 100644 --- a/test/units/utils.ts +++ b/test/units/utils.ts @@ -74,6 +74,7 @@ export const get = { } } +const configs: Map = new Map() const changedConfigs: Set = new Set() export const set = { root: (...paths: string[]) => { @@ -83,9 +84,12 @@ export const set = { lw.root.dir.path = path.dirname(rootFile) return rootFile }, - config: async (section: string, value: any) => { - await vscode.workspace.getConfiguration('latex-workshop').update(section, value) + config: (section: string, value: any) => { + configs.set(section, value) + }, + codeConfig: async (section: string, value: any) => { changedConfigs.add(section) + await vscode.workspace.getConfiguration('latex-workshop').update(section, value) } } @@ -99,9 +103,10 @@ export const reset = { }, config: async () => { for (const section of changedConfigs.values()) { - await set.config(section, undefined) + await set.codeConfig(section, undefined) } changedConfigs.clear() + configs.clear() }, log: () => { lwLog.resetCachedLog() @@ -129,6 +134,10 @@ export function sleep(ms: number) { } export const mock = { + init: (obj: any, ...ignore: string[]) => { + mock.object(obj, ...ignore) + mock.config() + }, object: (obj: any, ...ignore: string[]) => { const items = Object.getPrototypeOf(obj) === Object.prototype ? Object.getOwnPropertyNames(obj) @@ -145,6 +154,25 @@ export const mock = { } }) }, + config: () => { + const original = vscode.workspace.getConfiguration + sinon.stub(vscode.workspace, 'getConfiguration').callsFake((section?: string, scope?: vscode.ConfigurationScope | null) => { + function getConfig(configName: string): T | undefined + function getConfig(configName: string, defaultValue: T): T + function getConfig(configName: string, defaultValue?: T): T | undefined { + if (configs.has(configName)) { + return configs.get(configName) as T + } + return originalConfig.get(configName, defaultValue) + } + const originalConfig = original(section, scope) + const configItem: vscode.WorkspaceConfiguration = { + ...originalConfig, + get: getConfig + } + return configItem + }) + }, textDocument: (filePath: string, content: string, params: { languageId?: string, isDirty?: boolean, isClosed?: boolean, scheme?: string } = {}) => { return sinon.stub(vscode.workspace, 'textDocuments').value([ new TextDocument(filePath, content, params) ]) },