Skip to content

Commit

Permalink
Merge pull request #102 from SuperFlyTV/fix/cache-bug
Browse files Browse the repository at this point in the history
Bug fix: A changed object might not affect object on same layer
  • Loading branch information
nytamin authored Sep 4, 2024
2 parents 06cb211 + 677ee3d commit f960a1a
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 82 deletions.
96 changes: 96 additions & 0 deletions src/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
applyKeyframeContent,
} from '../index'
import { baseInstances } from '../resolver/lib/instance'
import { clone } from '../resolver/lib/lib'

describe('index', () => {
test('resolve timeline', () => {
Expand Down Expand Up @@ -783,4 +784,99 @@ describe('index', () => {
},
})
})

test('Cache', () => {
const timeline0: TimelineObject[] = [
{
id: 'bg',
enable: {
while: 1,
},
layer: 'layerA',
content: {},
},
{
id: 'group0',
enable: {
start: 10000,
},
layer: '',
content: {},
children: [
{
id: 'child0',
enable: {
start: 5000, // 15000
end: null,
},
layer: 'layerA',
content: {},
},
],
isGroup: true,
},
{
id: 'bg2',
enable: {
while: '#bg',
},
layer: 'layerB',
content: {},
priority: 1,
},
{
id: 'bg3',
enable: {
while: 1,
},
layer: 'layerB',
content: {},
priority: 0,
},
]

const timeline1 = clone(timeline0)

// Nudge "group0" a little bit, this should cause "child0" to be resolved differently, which in turn affects "bg" via collision
timeline1[1].enable = {
start: 10001,
}

const cache = {}

resolveTimeline(timeline0, { cache: cache, time: 0 })

const rtl1NoCache = resolveTimeline(timeline1, { time: 0 })
const rtl1 = resolveTimeline(timeline1, { cache: cache, time: 0 })

const state1NoCache = getResolvedState(rtl1NoCache, 10)
const state1 = getResolvedState(rtl1, 10)

// cache and no-cache should render the same result
expect(state1NoCache.layers['layerA']).toBeTruthy()

// "bg" should have changed, since that is affected by a collision with "child0"
expect(rtl1.objects['bg'].resolved.instances).toMatchObject([
{
start: 0,
end: 15001,
},
])
// "bg2" should have changed, since that is affected by the change to "bg"
expect(rtl1.objects['bg2'].resolved.instances).toMatchObject([
{
start: 0,
end: 15001,
},
])
// "bg3" should have changed, since that is affected by a collision with "bg2"
expect(rtl1.objects['bg3'].resolved.instances).toMatchObject([
{
start: 15001,
end: null,
},
])

expect(state1.layers['layerA']).toEqual(state1NoCache.layers['layerA'])
})
})
6 changes: 3 additions & 3 deletions src/__tests__/invalidate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describeVariants(
graphic1.enable.start = '#graphic0.end + 15' // 35

const resolved2 = resolveTimeline(timeline, { time: 0, cache })
expect(resolved2.statistics.resolvingObjectCount).toEqual(1)
expect(resolved2.statistics.resolvingObjectCount).toEqual(2)
expect(resolved2.objects['video'].resolved).toMatchObject({ instances: [{ start: 0, end: 100 }] })
expect(resolved2.objects['graphic0'].resolved).toMatchObject({ instances: [{ start: 10, end: 20 }] })
expect(resolved2.objects['graphic1'].resolved).toMatchObject({ instances: [{ start: 35, end: 50 }] })
Expand Down Expand Up @@ -121,7 +121,7 @@ describeVariants(

const resolved2 = resolveTimeline(timeline, { time: 0, cache })

expect(resolved2.statistics.resolvingObjectCount).toEqual(2)
expect(resolved2.statistics.resolvingObjectCount).toEqual(3)
expect(resolved2.objects['video0'].resolved.instances).toMatchObject([{ start: 20, end: 30 }])
expect(resolved2.objects['graphic0'].resolved.instances).toMatchObject([{ start: 30, end: 40 }])
expect(resolved2.objects['graphic1'].resolved.instances).toHaveLength(0)
Expand Down Expand Up @@ -261,7 +261,7 @@ describeVariants(
timeline.splice(index, 1)

const resolved3 = resolveTimeline(timeline, { time: 0, cache })
expect(resolved3.statistics.resolvingObjectCount).toEqual(1)
expect(resolved3.statistics.resolvingObjectCount).toEqual(2)
expect(resolved3.objects['video0'].resolved).toMatchObject({ instances: [{ start: 0, end: 100 }] })
expect(resolved3.objects['graphic0'].resolved).toMatchObject({ instances: [{ start: 10, end: 20 }] })
expect(resolved3.objects['graphic1'].resolved).toMatchObject({ instances: [{ start: 20, end: 25 }] })
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/performance.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('performance', () => {
test(
'performance test, no cache',
() => {
const { sortedTimes, executionTimeAvg } = doPerformanceTest(TEST_COUNT, false)
const { sortedTimes, executionTimeAvg } = doPerformanceTest(TEST_COUNT, TIMEOUT_TIME, false)
console.log(
`No Cache: Average time of execution: ${round(executionTimeAvg)} ms\n` +
'Worst 5:\n' +
Expand All @@ -29,7 +29,7 @@ describe('performance', () => {
test(
'performance test, with cache',
() => {
const { sortedTimes, executionTimeAvg } = doPerformanceTest(TEST_COUNT, true)
const { sortedTimes, executionTimeAvg } = doPerformanceTest(TEST_COUNT, TIMEOUT_TIME, true)
console.log(
`With cache: Average time of execution: ${round(executionTimeAvg)} ms\n` +
'Worst 5:\n' +
Expand Down
6 changes: 6 additions & 0 deletions src/__tests__/performance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const round = (num: number): number => {

export const doPerformanceTest = (
testCount: number,
timeoutTime: number,
useCache: boolean
): {
errorCount: number
Expand All @@ -48,8 +49,13 @@ export const doPerformanceTest = (

const testCountMax = testCount * 2

const startTime = Date.now()
for (let i = 0; i < testCountMax; i++) {
if (executionTimeCount >= testCount) break
const totalDuration = Date.now() - startTime
if (totalDuration >= timeoutTime) {
throw new Error(`Tests took too long (${totalDuration}ms)`)
}

seed++

Expand Down
Loading

0 comments on commit f960a1a

Please sign in to comment.