mirror of
1
0
Fork 0
ultimate-vim/sources_non_forked/coc.nvim/src/__tests__/handler/inlayHint.test.ts

234 lines
8.6 KiB
TypeScript

import { Neovim } from '@chemzqm/neovim'
import { CancellationTokenSource, Disposable, Position, Range } from 'vscode-languageserver-protocol'
import InlayHintHandler from '../../handler/inlayHint/index'
import { InlayHint } from '../../inlayHint'
import languages from '../../languages'
import { isValidInlayHint, sameHint } from '../../provider/inlayHintManager'
import { disposeAll } from '../../util'
import workspace from '../../workspace'
import helper from '../helper'
let nvim: Neovim
let handler: InlayHintHandler
let disposables: Disposable[] = []
let ns: number
beforeAll(async () => {
await helper.setup()
nvim = helper.nvim
handler = helper.plugin.getHandler().inlayHintHandler
ns = await nvim.createNamespace('coc-inlayHint')
})
afterAll(async () => {
await helper.shutdown()
})
afterEach(async () => {
disposeAll(disposables)
await helper.reset()
})
describe('InlayHint', () => {
describe('utils', () => {
it('should check same hint', () => {
let hint = InlayHint.create(Position.create(0, 0), 'foo')
expect(sameHint(hint, InlayHint.create(Position.create(0, 0), 'bar'))).toBe(false)
expect(sameHint(hint, InlayHint.create(Position.create(0, 0), [{ value: 'foo' }]))).toBe(true)
})
it('should check valid hint', () => {
let hint = InlayHint.create(Position.create(0, 0), 'foo')
expect(isValidInlayHint(hint, Range.create(0, 0, 1, 0))).toBe(true)
expect(isValidInlayHint(InlayHint.create(Position.create(0, 0), ''), Range.create(0, 0, 1, 0))).toBe(false)
expect(isValidInlayHint(InlayHint.create(Position.create(3, 0), 'foo'), Range.create(0, 0, 1, 0))).toBe(false)
expect(isValidInlayHint({ label: 'f' } as any, Range.create(0, 0, 1, 0))).toBe(false)
})
})
describe('provideInlayHints', () => {
it('should not throw when failed', async () => {
disposables.push(languages.registerInlayHintsProvider([{ language: '*' }], {
provideInlayHints: () => {
return Promise.reject(new Error('Test failure'))
}
}))
let doc = await workspace.document
let tokenSource = new CancellationTokenSource()
let res = await languages.provideInlayHints(doc.textDocument, Range.create(0, 0, 1, 0), tokenSource.token)
expect(res).toEqual([])
})
it('should merge provide results', async () => {
disposables.push(languages.registerInlayHintsProvider([{ language: '*' }], {
provideInlayHints: () => {
return [InlayHint.create(Position.create(0, 0), 'foo')]
}
}))
disposables.push(languages.registerInlayHintsProvider([{ language: '*' }], {
provideInlayHints: () => {
return [
InlayHint.create(Position.create(0, 0), 'foo'),
InlayHint.create(Position.create(1, 0), 'bar'),
InlayHint.create(Position.create(5, 0), 'bad')]
}
}))
let doc = await workspace.document
let tokenSource = new CancellationTokenSource()
let res = await languages.provideInlayHints(doc.textDocument, Range.create(0, 0, 3, 0), tokenSource.token)
expect(res.length).toBe(2)
})
it('should resolve inlay hint', async () => {
disposables.push(languages.registerInlayHintsProvider([{ language: '*' }], {
provideInlayHints: () => {
return [InlayHint.create(Position.create(0, 0), 'foo')]
},
resolveInlayHint: hint => {
hint.tooltip = 'tooltip'
return hint
}
}))
let doc = await workspace.document
let tokenSource = new CancellationTokenSource()
let res = await languages.provideInlayHints(doc.textDocument, Range.create(0, 0, 1, 0), tokenSource.token)
let resolved = await languages.resolveInlayHint(res[0], tokenSource.token)
expect(resolved.tooltip).toBe('tooltip')
resolved = await languages.resolveInlayHint(resolved, tokenSource.token)
expect(resolved.tooltip).toBe('tooltip')
})
it('should not resolve when cancelled', async () => {
disposables.push(languages.registerInlayHintsProvider([{ language: '*' }], {
provideInlayHints: () => {
return [InlayHint.create(Position.create(0, 0), 'foo')]
},
resolveInlayHint: (hint, token) => {
return new Promise(resolve => {
token.onCancellationRequested(() => {
clearTimeout(timer)
resolve(null)
})
let timer = setTimeout(() => {
resolve(Object.assign({}, hint, { tooltip: 'tooltip' }))
}, 200)
})
}
}))
let doc = await workspace.document
let tokenSource = new CancellationTokenSource()
let res = await languages.provideInlayHints(doc.textDocument, Range.create(0, 0, 1, 0), tokenSource.token)
let p = languages.resolveInlayHint(res[0], tokenSource.token)
tokenSource.cancel()
let resolved = await p
expect(resolved.tooltip).toBeUndefined()
})
})
describe('setVirtualText', () => {
async function registerProvider(content: string): Promise<Disposable> {
let doc = await workspace.document
let disposable = languages.registerInlayHintsProvider([{ language: '*' }], {
provideInlayHints: (document, range) => {
let content = document.getText(range)
let lines = content.split(/\r?\n/)
let hints: InlayHint[] = []
for (let i = 0; i < lines.length; i++) {
let line = lines[i]
if (!line.length) continue
let parts = line.split(/\s+/)
hints.push(...parts.map(s => InlayHint.create(Position.create(range.start.line + i, line.length), s)))
}
return hints
}
})
await doc.buffer.setLines(content.split(/\n/), { start: 0, end: -1 })
await doc.synchronize()
return disposable
}
async function waitRefresh(bufnr: number) {
let buf = handler.getItem(bufnr)
return new Promise<void>((resolve, reject) => {
let timer = setTimeout(() => {
reject(new Error('not refresh after 1s'))
}, 1000)
buf.onDidRefresh(() => {
clearTimeout(timer)
resolve()
})
})
}
it('should not refresh when languageId not match', async () => {
let doc = await workspace.document
disposables.push(languages.registerInlayHintsProvider([{ language: 'javascript' }], {
provideInlayHints: () => {
let hint = InlayHint.create(Position.create(0, 0), 'foo')
return [hint]
}
}))
await nvim.setLine('foo')
await doc.synchronize()
await helper.wait(30)
let markers = await doc.buffer.getExtMarks(ns, 0, -1, { details: true })
expect(markers.length).toBe(0)
})
it('should refresh on text change', async () => {
let buf = await nvim.buffer
let disposable = await registerProvider('foo')
disposables.push(disposable)
await waitRefresh(buf.id)
await buf.setLines(['a', 'b', 'c'], { start: 0, end: -1 })
await waitRefresh(buf.id)
let markers = await buf.getExtMarks(ns, 0, -1, { details: true })
expect(markers.length).toBe(3)
let item = handler.getItem(buf.id)
await item.renderRange()
expect(item.current.length).toBe(3)
})
it('should refresh on provider dispose', async () => {
let buf = await nvim.buffer
let disposable = await registerProvider('foo bar')
await waitRefresh(buf.id)
disposable.dispose()
let markers = await buf.getExtMarks(ns, 0, -1, { details: true })
expect(markers.length).toBe(0)
let item = handler.getItem(buf.id)
expect(item.current.length).toBe(0)
await item.renderRange()
expect(item.current.length).toBe(0)
})
it('should refresh on scroll', async () => {
let arr = new Array(200)
let content = arr.fill('foo').join('\n')
let buf = await nvim.buffer
let disposable = await registerProvider(content)
disposables.push(disposable)
await waitRefresh(buf.id)
let markers = await buf.getExtMarks(ns, 0, -1, { details: true })
let len = markers.length
await nvim.command('normal! G')
await waitRefresh(buf.id)
await nvim.input('<C-y>')
await waitRefresh(buf.id)
markers = await buf.getExtMarks(ns, 0, -1, { details: true })
expect(markers.length).toBeGreaterThan(len)
})
it('should cancel previous render', async () => {
let buf = await nvim.buffer
let disposable = await registerProvider('foo')
disposables.push(disposable)
await waitRefresh(buf.id)
let item = handler.getItem(buf.id)
await item.renderRange()
await item.renderRange()
expect(item.current.length).toBe(1)
})
})
})