mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-09 11:56:15 -08:00
139 lines
4.6 KiB
JavaScript
139 lines
4.6 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
// eslint-disable-next-line test/no-import-node-test -- Verify bounded encoding ownership with controlled native callbacks.
|
|
import test from 'node:test'
|
|
import { autoThumbnailCandidate, autoThumbnailEnvironment } from './helpers/auto-thumbnail.js'
|
|
|
|
const implementation = await autoThumbnailCandidate()
|
|
async function setup(number = 2) {
|
|
const env = autoThumbnailEnvironment(implementation)
|
|
await env.factory({ width: 80, number })(env.art)
|
|
env.art.emit('video:loadedmetadata')
|
|
env.metadata()
|
|
env.seeked()
|
|
return env
|
|
}
|
|
|
|
function closed(env) {
|
|
assert.equal(env.timers.size, 0)
|
|
assert.equal(env.attached.size, 0)
|
|
assert.equal(env.videos[0].src, undefined)
|
|
assert.equal(env.canvases[0].width, 0)
|
|
assert.equal(env.canvases[0].height, 0)
|
|
}
|
|
|
|
test('Auto-thumbnail stalled encoding closes owned resources and ignores a later Blob', async () => {
|
|
const env = await setup()
|
|
const timeout = [...env.timers.values()][0]
|
|
assert(timeout, 'Encoding must have an owned deadline after the frame wait finishes')
|
|
assert.equal(timeout.delay, 30000)
|
|
timeout.callback()
|
|
closed(env)
|
|
assert.equal(env.warnings.length, 1)
|
|
assert.match(env.warnings[0][1].message, /encoding timed out/)
|
|
env.finish()
|
|
timeout.callback()
|
|
assert.equal(env.updates.length, 0)
|
|
assert.equal(env.urls.size, 0)
|
|
assert.equal(env.warnings.length, 1)
|
|
env.art.emit('destroy')
|
|
})
|
|
|
|
test('Auto-thumbnail later encoding timeout preserves the last published preview', async () => {
|
|
const env = await setup()
|
|
env.finish()
|
|
const previous = env.art.thumbnails
|
|
env.seeked()
|
|
const timeout = [...env.timers.values()][0]
|
|
assert(timeout, 'The second encode needs a new deadline')
|
|
timeout.callback()
|
|
closed(env)
|
|
assert.equal(env.art.thumbnails, previous)
|
|
assert.equal(env.urls.has(previous.url), true)
|
|
env.finish(1)
|
|
assert.equal(env.updates.length, 1)
|
|
env.art.emit('destroy')
|
|
assert.equal(env.urls.size, 0)
|
|
})
|
|
|
|
for (const action of ['finish', 'destroy', 'restart']) {
|
|
test(`Auto-thumbnail ${action} invalidates an encoding deadline already queued for delivery`, async () => {
|
|
const env = await setup(1)
|
|
const timeout = [...env.timers.values()][0]
|
|
assert(timeout, 'Capture a real registered encoding deadline')
|
|
if (action === 'finish')
|
|
env.finish()
|
|
else env.art.emit(action)
|
|
timeout.callback()
|
|
env.finish()
|
|
closed(env)
|
|
assert.equal(env.warnings.length, 0)
|
|
assert.equal(env.updates.length, action === 'finish' ? 1 : 0)
|
|
env.art.emit('destroy')
|
|
assert.equal(env.urls.size, 0)
|
|
})
|
|
}
|
|
|
|
test('Auto-thumbnail completion clears only its own timeout before the next frame', async () => {
|
|
const env = await setup()
|
|
const timeout = [...env.timers.values()][0]
|
|
assert(timeout)
|
|
env.finish()
|
|
timeout.callback()
|
|
assert.equal(env.timers.size, 1, 'The next seek still owns its frame deadline')
|
|
env.seeked()
|
|
assert.equal(env.timers.size, 1, 'One encoding deadline replaces that frame deadline')
|
|
env.finish(1)
|
|
closed(env)
|
|
assert.equal(env.updates.length, 2)
|
|
assert.equal(env.warnings.length, 0)
|
|
env.art.emit('destroy')
|
|
})
|
|
|
|
test('Auto-thumbnail synchronous Blob delivery cancels its timeout and publishes once', async () => {
|
|
const env = autoThumbnailEnvironment(implementation)
|
|
await env.factory({ width: 80, number: 1 })(env.art)
|
|
env.art.emit('video:loadedmetadata')
|
|
env.metadata()
|
|
env.canvases[0].toBlob = (callback) => {
|
|
callback({ type: 'image/jpeg' })
|
|
callback({ type: 'image/jpeg' })
|
|
}
|
|
env.seeked()
|
|
closed(env)
|
|
assert.equal(env.updates.length, 1)
|
|
assert.equal(env.warnings.length, 0)
|
|
env.art.emit('destroy')
|
|
})
|
|
|
|
test('Auto-thumbnail deadline registration cannot start encoding across synchronous destruction', async () => {
|
|
const env = autoThumbnailEnvironment(implementation)
|
|
await env.factory({ width: 80, number: 1 })(env.art)
|
|
env.art.emit('video:loadedmetadata')
|
|
env.metadata()
|
|
const schedule = env.box.setTimeout
|
|
env.box.setTimeout = (...args) => {
|
|
env.art.emit('destroy')
|
|
return schedule(...args)
|
|
}
|
|
env.seeked()
|
|
closed(env)
|
|
assert.equal(env.blobs.length, 0)
|
|
assert.equal(env.warnings.length, 0)
|
|
})
|
|
|
|
test('Auto-thumbnail failed encoding deadline cleanup still releases canvas and decoder', async () => {
|
|
const env = await setup()
|
|
const clear = env.box.clearTimeout
|
|
const failure = new Error('Encoding timeout cleanup failed')
|
|
env.box.clearTimeout = (id) => {
|
|
clear(id)
|
|
throw failure
|
|
}
|
|
env.finish()
|
|
closed(env)
|
|
assert.equal(env.updates.length, 0)
|
|
assert.equal(env.warnings.length, 1)
|
|
assert.equal(env.warnings[0][1], failure)
|
|
env.art.emit('destroy')
|
|
})
|