172 lines
4.8 KiB
TypeScript
172 lines
4.8 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest'
|
|
import { ipcChannels } from '../shared/ipc-channels'
|
|
import { DocumentOcrBroker } from './document-ocr-broker'
|
|
|
|
function request() {
|
|
return {
|
|
modelId: 'pp-ocrv6-tiny',
|
|
fileName: 'scan.pdf',
|
|
mimeType: 'application/pdf' as const,
|
|
data: new ArrayBuffer(8),
|
|
maximumPages: 10,
|
|
pageNumbers: [1],
|
|
pageTimeoutSeconds: 60
|
|
}
|
|
}
|
|
|
|
describe('DocumentOcrBroker', () => {
|
|
it('forwards an AbortSignal cancellation to the renderer', async () => {
|
|
const send = vi.fn()
|
|
const broker = new DocumentOcrBroker({
|
|
isDestroyed: vi.fn(() => false),
|
|
webContents: { send }
|
|
} as never)
|
|
const controller = new AbortController()
|
|
const result = broker.recognize(request(), controller.signal)
|
|
const ocrRequest = send.mock.calls.find(
|
|
([channel]) => channel === ipcChannels.documentParsingOcrRequest
|
|
)?.[1] as { requestId: string }
|
|
|
|
controller.abort()
|
|
|
|
await expect(result).rejects.toThrow('OCR 解析已取消')
|
|
expect(send).toHaveBeenCalledWith(
|
|
ipcChannels.documentParsingOcrCancel,
|
|
ocrRequest.requestId
|
|
)
|
|
broker.dispose()
|
|
})
|
|
|
|
it('rejects a request that is already cancelled', () => {
|
|
const broker = new DocumentOcrBroker({
|
|
isDestroyed: vi.fn(() => false),
|
|
webContents: { send: vi.fn() }
|
|
} as never)
|
|
const controller = new AbortController()
|
|
controller.abort()
|
|
|
|
expect(() =>
|
|
broker.recognize(request(), controller.signal)
|
|
).toThrow('OCR 解析已取消')
|
|
broker.dispose()
|
|
})
|
|
|
|
it('rejects requests whose selected OCR pages exceed the limit', () => {
|
|
const broker = new DocumentOcrBroker({
|
|
isDestroyed: vi.fn(() => false),
|
|
webContents: { send: vi.fn() }
|
|
} as never)
|
|
|
|
expect(() =>
|
|
broker.recognize({
|
|
...request(),
|
|
maximumPages: 1,
|
|
pageNumbers: [1, 2]
|
|
})
|
|
).toThrow('OCR 页数超过当前文档限制')
|
|
broker.dispose()
|
|
})
|
|
|
|
it('queues OCR requests and starts timeout accounting on dispatch', async () => {
|
|
const send = vi.fn()
|
|
const broker = new DocumentOcrBroker({
|
|
isDestroyed: vi.fn(() => false),
|
|
webContents: { send }
|
|
} as never)
|
|
const first = broker.recognize(request())
|
|
const second = broker.recognize({
|
|
...request(),
|
|
fileName: 'second.pdf'
|
|
})
|
|
const requests = send.mock.calls.filter(
|
|
([channel]) => channel === ipcChannels.documentParsingOcrRequest
|
|
)
|
|
|
|
expect(requests).toHaveLength(1)
|
|
const firstRequest = requests[0]?.[1] as {
|
|
requestId: string
|
|
}
|
|
broker.respond({
|
|
requestId: firstRequest.requestId,
|
|
sections: [],
|
|
pageCount: 1,
|
|
warnings: []
|
|
})
|
|
await expect(first).resolves.toEqual(
|
|
expect.objectContaining({ requestId: firstRequest.requestId })
|
|
)
|
|
|
|
const dispatched = send.mock.calls.filter(
|
|
([channel]) => channel === ipcChannels.documentParsingOcrRequest
|
|
)
|
|
expect(dispatched).toHaveLength(2)
|
|
const secondRequest = dispatched[1]?.[1] as {
|
|
requestId: string
|
|
}
|
|
broker.respond({
|
|
requestId: secondRequest.requestId,
|
|
sections: [],
|
|
pageCount: 1,
|
|
warnings: []
|
|
})
|
|
await expect(second).resolves.toEqual(
|
|
expect.objectContaining({ requestId: secondRequest.requestId })
|
|
)
|
|
broker.dispose()
|
|
})
|
|
|
|
it('cancels a queued request without interrupting the active request', async () => {
|
|
const send = vi.fn()
|
|
const broker = new DocumentOcrBroker({
|
|
isDestroyed: vi.fn(() => false),
|
|
webContents: { send }
|
|
} as never)
|
|
const active = broker.recognize(request())
|
|
const controller = new AbortController()
|
|
const queued = broker.recognize(
|
|
{ ...request(), fileName: 'queued.pdf' },
|
|
controller.signal
|
|
)
|
|
|
|
controller.abort()
|
|
|
|
await expect(queued).rejects.toThrow('OCR 解析已取消')
|
|
expect(
|
|
send.mock.calls.filter(
|
|
([channel]) => channel === ipcChannels.documentParsingOcrCancel
|
|
)
|
|
).toHaveLength(0)
|
|
broker.dispose()
|
|
await expect(active).rejects.toThrow('OCR 解析已取消')
|
|
})
|
|
|
|
it('rejects OCR sections outside the requested page set', async () => {
|
|
const send = vi.fn()
|
|
const broker = new DocumentOcrBroker({
|
|
isDestroyed: vi.fn(() => false),
|
|
webContents: { send }
|
|
} as never)
|
|
const pending = broker.recognize(request())
|
|
const dispatched = send.mock.calls.find(
|
|
([channel]) => channel === ipcChannels.documentParsingOcrRequest
|
|
)?.[1] as { requestId: string }
|
|
|
|
broker.respond({
|
|
requestId: dispatched.requestId,
|
|
sections: [
|
|
{
|
|
locator: '第 2 页',
|
|
pageNumber: 2,
|
|
content: 'wrong page',
|
|
confidence: 0.9
|
|
}
|
|
],
|
|
pageCount: 2,
|
|
warnings: []
|
|
})
|
|
|
|
await expect(pending).rejects.toThrow('OCR 响应页码无效')
|
|
broker.dispose()
|
|
})
|
|
})
|