From b0734237d31037f7f2f370ae9fd7adcb8093ea56 Mon Sep 17 00:00:00 2001 From: Anton Kastritskiy Date: Wed, 15 Nov 2023 21:51:00 +0000 Subject: [PATCH] restructure tests + cache off tests --- src/spec/index.spec.ts | 634 ++++++++++++++++++++++++----------------- 1 file changed, 375 insertions(+), 259 deletions(-) diff --git a/src/spec/index.spec.ts b/src/spec/index.spec.ts index 77f61f3..14d18cb 100644 --- a/src/spec/index.spec.ts +++ b/src/spec/index.spec.ts @@ -14,21 +14,11 @@ jest.mock('fs', () => { ...fs, promises: { ...fs.promises, - readFile: jest.fn( - (...args: Parameters) => { - return fs.promises.readFile(...args); - }, - ), - access: jest.fn((pth: string) => { - return fs.promises.access(pth); - }), + readFile: jest.fn(fs.promises.readFile), + access: jest.fn(fs.promises.access), }, - accessSync: jest.fn((...args: Parameters) => { - return fs.accessSync(...args); - }), - readFileSync: jest.fn((...args: Parameters) => { - return fs.readFileSync(...args); - }), + accessSync: jest.fn(fs.accessSync), + readFileSync: jest.fn(fs.readFileSync), }; }); @@ -342,256 +332,382 @@ describe('options', () => { expect(ccResult).toEqual(expected); }); - // running all checks in one to avoid resetting cache for fs.promises.access - it('cache with async search()', async () => { - const stopDir = path.join(__dirname, 'search'); - const searchFrom = path.join(stopDir, 'a', 'b', 'c'); - const searchPlaces = ['cached.config.js', 'package.json']; - const searcher = lilconfig('cached', { - cache: true, - stopDir, - searchPlaces, - }); - const fsLookUps = () => - (fs.promises.access as jest.Mock).mock.calls.length; - - // per one search - // for unexisting - // (search + a + b + c) * times searchPlaces - - // for existing - // (search + a + b + c) * (times searchPlaces - **first** matched) - const expectedFsLookUps = 7; - - // initial search populates cache - const result = await searcher.search(searchFrom); - - expect(fsLookUps()).toBe(expectedFsLookUps); - - // subsequant search reads from cache - const result2 = await searcher.search(searchFrom); - expect(fsLookUps()).toBe(expectedFsLookUps); - expect(result).toEqual(result2); - - // searching a subpath reuses cache - const result3 = await searcher.search(path.join(stopDir, 'a')); - const result4 = await searcher.search(path.join(stopDir, 'a', 'b')); - expect(fsLookUps()).toBe(expectedFsLookUps); - expect(result2).toEqual(result3); - expect(result3).toEqual(result4); - - // calling clearCaches empties search cache - searcher.clearCaches(); - - // emptied all caches, should perform new lookups - const result5 = await searcher.search(searchFrom); - expect(fsLookUps()).toBe(expectedFsLookUps * 2); - expect(result4).toEqual(result5); - // different references - expect(result4 === result5).toEqual(false); - - searcher.clearSearchCache(); - const result6 = await searcher.search(searchFrom); - expect(fsLookUps()).toBe(expectedFsLookUps * 3); - expect(result5).toEqual(result6); - // different references - expect(result5 === result6).toEqual(false); - - // clearLoadCache does not clear search cache - searcher.clearLoadCache(); - const result7 = await searcher.search(searchFrom); - expect(fsLookUps()).toBe(expectedFsLookUps * 3); - expect(result6).toEqual(result7); - // same references - expect(result6 === result7).toEqual(true); - - // searching a superset path will access fs until it hits a known path - const result8 = await searcher.search(path.join(searchFrom, 'd')); - expect(fsLookUps()).toBe(3 * expectedFsLookUps + 2); - expect(result7).toEqual(result8); - // same references - expect(result7 === result8).toEqual(true); - - // repeated searches do not cause extra fs calls - const result9 = await searcher.search(path.join(searchFrom, 'd')); - expect(fsLookUps()).toBe(3 * expectedFsLookUps + 2); - expect(result8).toEqual(result9); - // same references - expect(result8 === result9).toEqual(true); - }); + describe('cache', () => { + // running all checks in one to avoid resetting cache for fs.promises.access + describe('enabled(default)', () => { + it('async search()', async () => { + const stopDir = path.join(__dirname, 'search'); + const searchFrom = path.join(stopDir, 'a', 'b', 'c'); + const searchPlaces = ['cached.config.js', 'package.json']; + const searcher = lilconfig('cached', { + cache: true, + stopDir, + searchPlaces, + }); + const fsLookUps = () => + (fs.promises.access as jest.Mock).mock.calls.length; - it('cache with sync search()', () => { - const stopDir = path.join(__dirname, 'search'); - const searchFrom = path.join(stopDir, 'a', 'b', 'c'); - const searchPlaces = ['cached.config.js', 'package.json']; - const searcher = lilconfigSync('cached', { - cache: true, - stopDir, - searchPlaces, - }); - const fsLookUps = () => (fs.accessSync as jest.Mock).mock.calls.length; - - // per one search - // for unexisting - // (search + a + b + c) * times searchPlaces - - // for existing - // (search + a + b + c) * (times searchPlaces - **first** matched) - const expectedFsLookUps = 7; - - // initial search populates cache - const result = searcher.search(searchFrom); - - expect(fsLookUps()).toBe(expectedFsLookUps); - - // subsequant search reads from cache - const result2 = searcher.search(searchFrom); - expect(fsLookUps()).toBe(expectedFsLookUps); - expect(result).toEqual(result2); - - // searching a subpath reuses cache - const result3 = searcher.search(path.join(stopDir, 'a')); - const result4 = searcher.search(path.join(stopDir, 'a', 'b')); - expect(fsLookUps()).toBe(expectedFsLookUps); - expect(result2).toEqual(result3); - expect(result3).toEqual(result4); - - // calling clearCaches empties search cache - searcher.clearCaches(); - - // emptied all caches, should perform new lookups - const result5 = searcher.search(searchFrom); - expect(fsLookUps()).toBe(expectedFsLookUps * 2); - expect(result4).toEqual(result5); - // different references - expect(result4 === result5).toEqual(false); - - searcher.clearSearchCache(); - const result6 = searcher.search(searchFrom); - expect(fsLookUps()).toBe(expectedFsLookUps * 3); - expect(result5).toEqual(result6); - // different references - expect(result5 === result6).toEqual(false); - - // clearLoadCache does not clear search cache - searcher.clearLoadCache(); - const result7 = searcher.search(searchFrom); - expect(fsLookUps()).toBe(expectedFsLookUps * 3); - expect(result6).toEqual(result7); - // same references - expect(result6 === result7).toEqual(true); - - // searching a superset path will access fs until it hits a known path - const result8 = searcher.search(path.join(searchFrom, 'd')); - expect(fsLookUps()).toBe(3 * expectedFsLookUps + 2); - expect(result7).toEqual(result8); - // same references - expect(result7 === result8).toEqual(true); - - // repeated searches do not cause extra fs calls - const result9 = searcher.search(path.join(searchFrom, 'd')); - expect(fsLookUps()).toBe(3 * expectedFsLookUps + 2); - expect(result8).toEqual(result9); - // same references - expect(result8 === result9).toEqual(true); - }); + expect(fsLookUps()).toBe(0); - it('cache with async load()', async () => { - const stopDir = path.join(__dirname, 'search'); - const searchPlaces = ['cached.config.js', 'package.json']; - const searcher = lilconfig('cached', { - cache: true, - stopDir, - searchPlaces, + // per one search + // for unexisting + // (search + a + b + c) * times searchPlaces + + // for existing + // (search + a + b + c) * (times searchPlaces - **first** matched) + const expectedFsLookUps = 7; + + // initial search populates cache + const result = await searcher.search(searchFrom); + + expect(fsLookUps()).toBe(expectedFsLookUps); + + // subsequant search reads from cache + const result2 = await searcher.search(searchFrom); + expect(fsLookUps()).toBe(expectedFsLookUps); + expect(result).toEqual(result2); + + // searching a subpath reuses cache + const result3 = await searcher.search(path.join(stopDir, 'a')); + const result4 = await searcher.search( + path.join(stopDir, 'a', 'b'), + ); + expect(fsLookUps()).toBe(expectedFsLookUps); + expect(result2).toEqual(result3); + expect(result3).toEqual(result4); + + // calling clearCaches empties search cache + searcher.clearCaches(); + + // emptied all caches, should perform new lookups + const result5 = await searcher.search(searchFrom); + expect(fsLookUps()).toBe(expectedFsLookUps * 2); + expect(result4).toEqual(result5); + // different references + expect(result4 === result5).toEqual(false); + + searcher.clearSearchCache(); + const result6 = await searcher.search(searchFrom); + expect(fsLookUps()).toBe(expectedFsLookUps * 3); + expect(result5).toEqual(result6); + // different references + expect(result5 === result6).toEqual(false); + + // clearLoadCache does not clear search cache + searcher.clearLoadCache(); + const result7 = await searcher.search(searchFrom); + expect(fsLookUps()).toBe(expectedFsLookUps * 3); + expect(result6).toEqual(result7); + // same references + expect(result6 === result7).toEqual(true); + + // searching a superset path will access fs until it hits a known path + const result8 = await searcher.search( + path.join(searchFrom, 'd'), + ); + expect(fsLookUps()).toBe(3 * expectedFsLookUps + 2); + expect(result7).toEqual(result8); + // same references + expect(result7 === result8).toEqual(true); + + // repeated searches do not cause extra fs calls + const result9 = await searcher.search( + path.join(searchFrom, 'd'), + ); + expect(fsLookUps()).toBe(3 * expectedFsLookUps + 2); + expect(result8).toEqual(result9); + // same references + expect(result8 === result9).toEqual(true); + }); + + it('sync search()', () => { + const stopDir = path.join(__dirname, 'search'); + const searchFrom = path.join(stopDir, 'a', 'b', 'c'); + const searchPlaces = ['cached.config.js', 'package.json']; + const searcher = lilconfigSync('cached', { + cache: true, + stopDir, + searchPlaces, + }); + const fsLookUps = () => + (fs.accessSync as jest.Mock).mock.calls.length; + + expect(fsLookUps()).toBe(0); + + // per one search + // for unexisting + // (search + a + b + c) * times searchPlaces + + // for existing + // (search + a + b + c) * (times searchPlaces - **first** matched) + const expectedFsLookUps = 7; + + // initial search populates cache + const result = searcher.search(searchFrom); + + expect(fsLookUps()).toBe(expectedFsLookUps); + + // subsequant search reads from cache + const result2 = searcher.search(searchFrom); + expect(fsLookUps()).toBe(expectedFsLookUps); + expect(result).toEqual(result2); + + // searching a subpath reuses cache + const result3 = searcher.search(path.join(stopDir, 'a')); + const result4 = searcher.search(path.join(stopDir, 'a', 'b')); + expect(fsLookUps()).toBe(expectedFsLookUps); + expect(result2).toEqual(result3); + expect(result3).toEqual(result4); + + // calling clearCaches empties search cache + searcher.clearCaches(); + + // emptied all caches, should perform new lookups + const result5 = searcher.search(searchFrom); + expect(fsLookUps()).toBe(expectedFsLookUps * 2); + expect(result4).toEqual(result5); + // different references + expect(result4 === result5).toEqual(false); + + searcher.clearSearchCache(); + const result6 = searcher.search(searchFrom); + expect(fsLookUps()).toBe(expectedFsLookUps * 3); + expect(result5).toEqual(result6); + // different references + expect(result5 === result6).toEqual(false); + + // clearLoadCache does not clear search cache + searcher.clearLoadCache(); + const result7 = searcher.search(searchFrom); + expect(fsLookUps()).toBe(expectedFsLookUps * 3); + expect(result6).toEqual(result7); + // same references + expect(result6 === result7).toEqual(true); + + // searching a superset path will access fs until it hits a known path + const result8 = searcher.search(path.join(searchFrom, 'd')); + expect(fsLookUps()).toBe(3 * expectedFsLookUps + 2); + expect(result7).toEqual(result8); + // same references + expect(result7 === result8).toEqual(true); + + // repeated searches do not cause extra fs calls + const result9 = searcher.search(path.join(searchFrom, 'd')); + expect(fsLookUps()).toBe(3 * expectedFsLookUps + 2); + expect(result8).toEqual(result9); + // same references + expect(result8 === result9).toEqual(true); + }); + + it('async load()', async () => { + const stopDir = path.join(__dirname, 'search'); + const searchPlaces = ['cached.config.js', 'package.json']; + const searcher = lilconfig('cached', { + cache: true, + stopDir, + searchPlaces, + }); + const existingFile = path.join(stopDir, 'cached.config.js'); + const fsReadFileCalls = () => + (fs.promises.readFile as jest.Mock).mock.calls.length; + + expect(fsReadFileCalls()).toBe(0); + + // initial search populates cache + const result = await searcher.load(existingFile); + expect(fsReadFileCalls()).toBe(1); + + // subsequant load reads from cache + const result2 = await searcher.load(existingFile); + expect(fsReadFileCalls()).toBe(1); + expect(result).toEqual(result2); + // same reference + expect(result === result2).toEqual(true); + + // calling clearCaches empties search cache + searcher.clearCaches(); + const result3 = await searcher.load(existingFile); + expect(fsReadFileCalls()).toBe(2); + expect(result2).toEqual(result3); + // different reference + expect(result2 === result3).toEqual(false); + + searcher.clearLoadCache(); + const result4 = await searcher.load(existingFile); + expect(fsReadFileCalls()).toBe(3); + expect(result3).toEqual(result4); + // different reference + expect(result3 === result4).toEqual(false); + + // clearLoadCache does not clear search cache + searcher.clearSearchCache(); + const result5 = await searcher.load(existingFile); + expect(fsReadFileCalls()).toBe(3); + expect(result4).toEqual(result5); + // same reference + expect(result4 === result5).toEqual(true); + }); + + it('sync load()', () => { + const stopDir = path.join(__dirname, 'search'); + const searchPlaces = ['cached.config.js', 'package.json']; + const searcher = lilconfigSync('cached', { + cache: true, + stopDir, + searchPlaces, + }); + const existingFile = path.join(stopDir, 'cached.config.js'); + const fsReadFileCalls = () => + (fs.readFileSync as jest.Mock).mock.calls.length; + + expect(fsReadFileCalls()).toBe(0); + + // initial search populates cache + const result = searcher.load(existingFile); + expect(fsReadFileCalls()).toBe(1); + + // subsequant load reads from cache + const result2 = searcher.load(existingFile); + expect(fsReadFileCalls()).toBe(1); + expect(result).toEqual(result2); + // same reference + expect(result === result2).toEqual(true); + + // calling clearCaches empties search cache + searcher.clearCaches(); + const result3 = searcher.load(existingFile); + expect(fsReadFileCalls()).toBe(2); + expect(result2).toEqual(result3); + // different reference + expect(result2 === result3).toEqual(false); + + searcher.clearLoadCache(); + const result4 = searcher.load(existingFile); + expect(fsReadFileCalls()).toBe(3); + expect(result3).toEqual(result4); + // different reference + expect(result3 === result4).toEqual(false); + + // clearLoadCache does not clear search cache + searcher.clearSearchCache(); + const result5 = searcher.load(existingFile); + expect(fsReadFileCalls()).toBe(3); + expect(result4).toEqual(result5); + // same reference + expect(result4 === result5).toEqual(true); + }); }); - const existingFile = path.join(stopDir, 'cached.config.js'); - const fsReadFileCalls = () => - (fs.promises.readFile as jest.Mock).mock.calls.length; - - expect(fsReadFileCalls()).toBe(0); - - // initial search populates cache - const result = await searcher.load(existingFile); - expect(fsReadFileCalls()).toBe(1); - - // subsequant load reads from cache - const result2 = await searcher.load(existingFile); - expect(fsReadFileCalls()).toBe(1); - expect(result).toEqual(result2); - // same reference - expect(result === result2).toEqual(true); - - // calling clearCaches empties search cache - searcher.clearCaches(); - const result3 = await searcher.load(existingFile); - expect(fsReadFileCalls()).toBe(2); - expect(result2).toEqual(result3); - // different reference - expect(result2 === result3).toEqual(false); - - searcher.clearLoadCache(); - const result4 = await searcher.load(existingFile); - expect(fsReadFileCalls()).toBe(3); - expect(result3).toEqual(result4); - // different reference - expect(result3 === result4).toEqual(false); - - // clearLoadCache does not clear search cache - searcher.clearSearchCache(); - const result5 = await searcher.load(existingFile); - expect(fsReadFileCalls()).toBe(3); - expect(result4).toEqual(result5); - // same reference - expect(result4 === result5).toEqual(true); - }); + describe('disabled', () => { + it('async search()', async () => { + const stopDir = path.join(__dirname, 'search'); + const searchFrom = path.join(stopDir, 'a', 'b', 'c'); + const searchPlaces = ['cached.config.js', 'package.json']; + const searcher = lilconfig('cached', { + cache: false, + stopDir, + searchPlaces, + }); + const fsLookUps = () => + (fs.promises.access as jest.Mock).mock.calls.length; - it('cache with sync load()', () => { - const stopDir = path.join(__dirname, 'search'); - const searchPlaces = ['cached.config.js', 'package.json']; - const searcher = lilconfigSync('cached', { - cache: true, - stopDir, - searchPlaces, + expect(fsLookUps()).toBe(0); + + const expectedFsLookUps = 7; + + // initial search populates cache + const result = await searcher.search(searchFrom); + + expect(fsLookUps()).toBe(expectedFsLookUps); + + // subsequant search reads from cache + const result2 = await searcher.search(searchFrom); + expect(fsLookUps()).toBe(expectedFsLookUps * 2); + expect(result).toEqual(result2); + + expect(result2 === result).toBe(false); + }); + + it('sync search()', () => { + const stopDir = path.join(__dirname, 'search'); + const searchFrom = path.join(stopDir, 'a', 'b', 'c'); + const searchPlaces = ['cached.config.js', 'package.json']; + const searcher = lilconfigSync('cached', { + cache: false, + stopDir, + searchPlaces, + }); + const fsLookUps = () => + (fs.accessSync as jest.Mock).mock.calls.length; + + expect(fsLookUps()).toBe(0); + + const expectedFsLookUps = 7; + + // initial search populates cache + const result = searcher.search(searchFrom); + + expect(fsLookUps()).toBe(expectedFsLookUps); + + // subsequent search reads from cache + const result2 = searcher.search(searchFrom); + expect(fsLookUps()).toBe(expectedFsLookUps * 2); + expect(result).toEqual(result2); + + expect(result2 === result).toBe(false); + }); + + it('async load()', async () => { + const stopDir = path.join(__dirname, 'search'); + const searchPlaces = ['cached.config.js', 'package.json']; + const searcher = lilconfig('cached', { + cache: false, + stopDir, + searchPlaces, + }); + const existingFile = path.join(stopDir, 'cached.config.js'); + const fsReadFileCalls = () => + (fs.promises.readFile as jest.Mock).mock.calls.length; + + expect(fsReadFileCalls()).toBe(0); + + // initial search populates cache + const result = await searcher.load(existingFile); + expect(fsReadFileCalls()).toBe(1); + + // subsequant load reads from cache + const result2 = await searcher.load(existingFile); + expect(fsReadFileCalls()).toBe(2); + expect(result).toEqual(result2); + // different reference + expect(result === result2).toEqual(false); + }); + + it('sync load()', () => { + const stopDir = path.join(__dirname, 'search'); + const searchPlaces = ['cached.config.js', 'package.json']; + const searcher = lilconfigSync('cached', { + cache: false, + stopDir, + searchPlaces, + }); + const existingFile = path.join(stopDir, 'cached.config.js'); + const fsReadFileCalls = () => + (fs.readFileSync as jest.Mock).mock.calls.length; + + expect(fsReadFileCalls()).toBe(0); + + // initial search populates cache + const result = searcher.load(existingFile); + expect(fsReadFileCalls()).toBe(1); + + // subsequant load reads from cache + const result2 = searcher.load(existingFile); + expect(fsReadFileCalls()).toBe(2); + expect(result).toEqual(result2); + // differnt reference + expect(result === result2).toEqual(false); + }); }); - const existingFile = path.join(stopDir, 'cached.config.js'); - const fsReadFileCalls = () => - (fs.readFileSync as jest.Mock).mock.calls.length; - - expect(fsReadFileCalls()).toBe(0); - - // initial search populates cache - const result = searcher.load(existingFile); - expect(fsReadFileCalls()).toBe(1); - - // subsequant load reads from cache - const result2 = searcher.load(existingFile); - expect(fsReadFileCalls()).toBe(1); - expect(result).toEqual(result2); - // same reference - expect(result === result2).toEqual(true); - - // calling clearCaches empties search cache - searcher.clearCaches(); - const result3 = searcher.load(existingFile); - expect(fsReadFileCalls()).toBe(2); - expect(result2).toEqual(result3); - // different reference - expect(result2 === result3).toEqual(false); - - searcher.clearLoadCache(); - const result4 = searcher.load(existingFile); - expect(fsReadFileCalls()).toBe(3); - expect(result3).toEqual(result4); - // different reference - expect(result3 === result4).toEqual(false); - - // clearLoadCache does not clear search cache - searcher.clearSearchCache(); - const result5 = searcher.load(existingFile); - expect(fsReadFileCalls()).toBe(3); - expect(result4).toEqual(result5); - // same reference - expect(result4 === result5).toEqual(true); }); describe('packageProp', () => {