| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- import { ReferenceIndexer } from '@/features/ide-react/references/reference-indexer'
- import { generateMD5Hash } from '@/shared/utils/md5'
- import sinon from 'sinon'
- const entry1 = `@article{sample2023,
- author = {John Doe},
- title = {Sample Title},
- journal = {Sample Journal},
- year = {2023},
- date = {2023-01-01}
- }`
- const entry2 = `@book{example2022,
- author = {Jane Smith},
- title = {Example Book},
- journal = {Example Journal},
- year = {2022}
- date = {2022-05-15}
- }`
- const entry3 = `@article{sample2024,
- author = {John Doe},
- title = {Sample Title},
- journal = {Sample Journal},
- year = {2024},
- date = {2024-01-01}
- }`
- const entry4 = `@book{example2025,
- author = {Jane Smith},
- title = {Example Book},
- journal = {Example Journal},
- year = {2025}
- date = {2025-05-15}
- }`
- const snapshotWithData = ({
- docs,
- files,
- }: {
- docs?: Record<string, string>
- files?: Record<string, string>
- }) => {
- return {
- getDocPaths: sinon.spy(() => Object.keys(docs ?? {})),
- getDocContents: sinon.spy(path => (docs ? (docs[path] ?? null) : null)),
- getBinaryFilePathsWithHash: sinon.spy(() => {
- return Object.entries(files ?? {}).map(([path, content]) => ({
- path,
- hash: generateMD5Hash(content),
- size: content.length,
- }))
- }),
- getBinaryFileContents: sinon.spy(async path =>
- files ? (files[path] ?? null) : null
- ),
- }
- }
- const IGNORED_SIGNAL = new AbortController().signal
- describe('ReferenceIndexer', function () {
- it('it should index bib docs', async function () {
- const referencer = new ReferenceIndexer()
- const snapshot = snapshotWithData({
- docs: {
- 'refs.bib': entry1,
- 'refs2.bib': entry2,
- 'other.tex': 'Not a bib file',
- },
- })
- const result = await referencer.updateFromSnapshot(snapshot, {
- signal: IGNORED_SIGNAL,
- })
- expect(snapshot.getDocPaths).to.have.been.calledOnce
- expect(snapshot.getDocContents).to.have.been.calledTwice
- expect(snapshot.getDocContents).to.have.been.calledWith('refs.bib')
- expect(snapshot.getDocContents).to.have.been.calledWith('refs2.bib')
- expect(snapshot.getDocContents).to.not.have.been.calledWith('other.tex')
- expect(snapshot.getBinaryFileContents).to.not.have.been.called
- expect(result).to.deep.equal(new Set(['sample2023', 'example2022']))
- })
- it('it should index bib binary files', async function () {
- const referencer = new ReferenceIndexer()
- const snapshot = snapshotWithData({
- files: {
- 'refs.bib': entry1,
- 'refs2.bib': entry2,
- 'image.png': 'Not a bib file',
- },
- })
- const result = await referencer.updateFromSnapshot(snapshot, {
- signal: IGNORED_SIGNAL,
- })
- expect(snapshot.getDocPaths).to.have.been.calledOnce
- expect(snapshot.getDocContents).to.not.have.been.called
- expect(snapshot.getBinaryFilePathsWithHash).to.have.been.calledOnce
- expect(snapshot.getBinaryFileContents).to.have.been.calledTwice
- expect(snapshot.getBinaryFileContents).to.have.been.calledWith('refs.bib')
- expect(snapshot.getBinaryFileContents).to.have.been.calledWith('refs2.bib')
- expect(snapshot.getBinaryFileContents).to.not.have.been.calledWith(
- 'image.png'
- )
- expect(result).to.deep.equal(new Set(['sample2023', 'example2022']))
- })
- it('it should index both bib docs and binary files', async function () {
- const referencer = new ReferenceIndexer()
- const snapshot = snapshotWithData({
- docs: {
- 'refs.bib': entry1,
- 'other.tex': 'Not a bib file',
- },
- files: {
- 'refs2.bib': entry2,
- 'image.png': 'Not a bib file',
- },
- })
- const result = await referencer.updateFromSnapshot(snapshot, {
- signal: IGNORED_SIGNAL,
- })
- expect(snapshot.getDocPaths).to.have.been.calledOnce
- expect(snapshot.getDocContents).to.have.been.calledOnce
- expect(snapshot.getDocContents).to.have.been.calledWith('refs.bib')
- expect(snapshot.getDocContents).to.not.have.been.calledWith('other.tex')
- expect(snapshot.getBinaryFilePathsWithHash).to.have.been.calledOnce
- expect(snapshot.getBinaryFileContents).to.have.been.calledOnce
- expect(snapshot.getBinaryFileContents).to.have.been.calledWith('refs2.bib')
- expect(snapshot.getBinaryFileContents).to.not.have.been.calledWith(
- 'image.png'
- )
- expect(result).to.deep.equal(new Set(['sample2023', 'example2022']))
- })
- it('should not fetch binary files if unchanged', async function () {
- const referencer = new ReferenceIndexer()
- const initialSnapshot = snapshotWithData({
- files: {
- 'refs.bib': entry1,
- },
- })
- const initialResult = await referencer.updateFromSnapshot(initialSnapshot, {
- signal: IGNORED_SIGNAL,
- })
- expect(initialSnapshot.getDocPaths).to.have.been.calledOnce
- expect(initialSnapshot.getBinaryFilePathsWithHash).to.have.been.calledOnce
- expect(initialSnapshot.getBinaryFileContents).to.have.been.calledOnceWith(
- 'refs.bib'
- )
- expect(initialResult).to.deep.equal(new Set(['sample2023']))
- // Second snapshot with same files, should not fetch contents again
- const secondSnapshot = snapshotWithData({
- files: {
- 'refs.bib': entry1,
- },
- })
- const secondResult = await referencer.updateFromSnapshot(secondSnapshot, {
- signal: IGNORED_SIGNAL,
- })
- expect(secondSnapshot.getDocPaths).to.have.been.calledOnce
- expect(secondSnapshot.getBinaryFilePathsWithHash).to.have.been.calledOnce
- expect(secondSnapshot.getBinaryFileContents).to.not.have.been.called
- expect(secondResult).to.deep.equal(new Set(['sample2023']))
- })
- it('should fetch changed binary file', async function () {
- const referencer = new ReferenceIndexer()
- const initialSnapshot = snapshotWithData({
- files: {
- 'refs.bib': entry1,
- },
- })
- const initialResult = await referencer.updateFromSnapshot(initialSnapshot, {
- signal: IGNORED_SIGNAL,
- })
- expect(initialSnapshot.getDocPaths).to.have.been.calledOnce
- expect(initialSnapshot.getBinaryFilePathsWithHash).to.have.been.calledOnce
- expect(initialSnapshot.getBinaryFileContents).to.have.been.calledOnceWith(
- 'refs.bib'
- )
- expect(initialResult).to.deep.equal(new Set(['sample2023']))
- // Second snapshot with a different file, should fetch contents again
- const secondSnapshot = snapshotWithData({
- files: {
- 'refs.bib': entry2,
- },
- })
- const secondResult = await referencer.updateFromSnapshot(secondSnapshot, {
- signal: IGNORED_SIGNAL,
- })
- expect(secondSnapshot.getDocPaths).to.have.been.calledOnce
- expect(secondSnapshot.getBinaryFilePathsWithHash).to.have.been.calledOnce
- expect(initialSnapshot.getBinaryFileContents).to.have.been.calledOnceWith(
- 'refs.bib'
- )
- expect(secondResult).to.deep.equal(new Set(['example2022']))
- })
- it('should update changed doc', async function () {
- const referencer = new ReferenceIndexer()
- const initialSnapshot = snapshotWithData({
- docs: {
- 'refs.bib': entry1,
- },
- })
- const initialResult = await referencer.updateFromSnapshot(initialSnapshot, {
- signal: IGNORED_SIGNAL,
- })
- expect(initialResult).to.deep.equal(new Set(['sample2023']))
- const secondSnapshot = snapshotWithData({
- docs: {
- 'refs.bib': entry2,
- },
- })
- const secondResult = await referencer.updateFromSnapshot(secondSnapshot, {
- signal: IGNORED_SIGNAL,
- })
- expect(secondResult).to.deep.equal(new Set(['example2022']))
- })
- it('should notice deleted files', async function () {
- const referencer = new ReferenceIndexer()
- const initialSnapshot = snapshotWithData({
- files: {
- 'refs.bib': entry1,
- 'refs2.bib': entry2,
- },
- })
- const initialResult = await referencer.updateFromSnapshot(initialSnapshot, {
- signal: IGNORED_SIGNAL,
- })
- expect(initialSnapshot.getDocPaths).to.have.been.calledOnce
- expect(initialSnapshot.getBinaryFilePathsWithHash).to.have.been.calledOnce
- expect(initialSnapshot.getBinaryFileContents).to.have.been.calledTwice
- expect(initialResult).to.deep.equal(new Set(['sample2023', 'example2022']))
- // Second snapshot with one file removed, should update index
- const secondSnapshot = snapshotWithData({
- files: {
- 'refs.bib': entry1,
- },
- })
- const secondResult = await referencer.updateFromSnapshot(secondSnapshot, {
- signal: IGNORED_SIGNAL,
- })
- expect(secondSnapshot.getDocPaths).to.have.been.calledOnce
- expect(secondSnapshot.getBinaryFilePathsWithHash).to.have.been.calledOnce
- expect(secondSnapshot.getBinaryFileContents).to.not.have.been.called
- expect(secondResult).to.deep.equal(new Set(['sample2023']))
- })
- it('should notice deleted docs', async function () {
- const referencer = new ReferenceIndexer()
- const initialSnapshot = snapshotWithData({
- docs: {
- 'refs.bib': entry1,
- 'refs2.bib': entry2,
- },
- })
- const initialResult = await referencer.updateFromSnapshot(initialSnapshot, {
- signal: IGNORED_SIGNAL,
- })
- expect(initialSnapshot.getDocPaths).to.have.been.calledOnce
- expect(initialSnapshot.getDocContents).to.have.been.calledTwice
- expect(initialResult).to.deep.equal(new Set(['sample2023', 'example2022']))
- // Second snapshot with one doc removed, should update index
- const secondSnapshot = snapshotWithData({
- docs: {
- 'refs.bib': entry1,
- },
- })
- const secondResult = await referencer.updateFromSnapshot(secondSnapshot, {
- signal: IGNORED_SIGNAL,
- })
- expect(secondSnapshot.getDocPaths).to.have.been.calledOnce
- expect(secondSnapshot.getDocContents).to.have.been.calledOnce
- expect(secondResult).to.deep.equal(new Set(['sample2023']))
- })
- it('should abort when signalled', async function () {
- const referencer = new ReferenceIndexer()
- const snapshot = snapshotWithData({
- files: {
- 'refs.bib': entry1,
- 'refs2.bib': entry2,
- },
- })
- const controller = new AbortController()
- controller.abort()
- const result = await referencer.updateFromSnapshot(snapshot, {
- signal: controller.signal,
- })
- expect(result).to.deep.equal(new Set())
- })
- it('should respect data budget', async function () {
- async function testWithDataBudget(budget: number, keys: Set<string>) {
- const referencer = new ReferenceIndexer()
- const snapshot = snapshotWithData({
- docs: {
- 'a.bib': entry1, // 140 bytes
- 'b.bib': entry2, // 140 bytes
- 'c.bib': entry3, // 140 bytes
- 'd.bib': entry4, // 140 bytes
- },
- })
- const result = await referencer.updateFromSnapshot(snapshot, {
- signal: IGNORED_SIGNAL,
- dataLimit: budget,
- })
- expect(result).to.deep.equal(keys)
- }
- await testWithDataBudget(
- 1000,
- new Set(['sample2023', 'example2022', 'sample2024', 'example2025'])
- )
- await testWithDataBudget(300, new Set(['sample2023', 'example2022']))
- await testWithDataBudget(200, new Set(['sample2023']))
- await testWithDataBudget(100, new Set())
- })
- })
|