|
9 | 9 | import { describe, expect, it } from "bun:test"; |
10 | 10 | import { |
11 | 11 | BROWSER_GPU_NOT_SOFTWARE, |
| 12 | + DISTRIBUTED_DURATION_OUT_OF_RANGE, |
| 13 | + MAX_DISTRIBUTED_DURATION_SECONDS, |
12 | 14 | PlanValidationError, |
13 | 15 | SYSTEM_FONT_USED, |
14 | 16 | parseFontFamilyValue, |
| 17 | + validateDistributedDuration, |
15 | 18 | validateNoGpuEncode, |
16 | 19 | validateNoSystemFonts, |
17 | 20 | } from "./planValidation.js"; |
@@ -91,6 +94,53 @@ describe("validateNoGpuEncode", () => { |
91 | 94 | }); |
92 | 95 | }); |
93 | 96 |
|
| 97 | +describe("validateDistributedDuration", () => { |
| 98 | + it("accepts a finite duration within the distributed ceiling", () => { |
| 99 | + expect(() => |
| 100 | + validateDistributedDuration({ |
| 101 | + duration: MAX_DISTRIBUTED_DURATION_SECONDS, |
| 102 | + totalFrames: MAX_DISTRIBUTED_DURATION_SECONDS * 30, |
| 103 | + fps: 30, |
| 104 | + }), |
| 105 | + ).not.toThrow(); |
| 106 | + }); |
| 107 | + |
| 108 | + it("throws DISTRIBUTED_DURATION_OUT_OF_RANGE for the engine's infinite-timeline sentinel", () => { |
| 109 | + let caught: unknown; |
| 110 | + try { |
| 111 | + validateDistributedDuration({ |
| 112 | + duration: 10_000_000_000, |
| 113 | + totalFrames: 300_000_000_000, |
| 114 | + fps: 30, |
| 115 | + }); |
| 116 | + } catch (err) { |
| 117 | + caught = err; |
| 118 | + } |
| 119 | + expect(caught).toBeInstanceOf(PlanValidationError); |
| 120 | + expect((caught as PlanValidationError).code).toBe(DISTRIBUTED_DURATION_OUT_OF_RANGE); |
| 121 | + expect((caught as Error).message).toContain("300000000000"); |
| 122 | + expect((caught as Error).message).toContain("GSAP repeat:-1"); |
| 123 | + }); |
| 124 | + |
| 125 | + it("throws DISTRIBUTED_DURATION_OUT_OF_RANGE for non-finite or zero values", () => { |
| 126 | + for (const input of [ |
| 127 | + { duration: Number.POSITIVE_INFINITY, totalFrames: 1, fps: 30 }, |
| 128 | + { duration: 0, totalFrames: 1, fps: 30 }, |
| 129 | + { duration: 1, totalFrames: 0, fps: 30 }, |
| 130 | + { duration: 1, totalFrames: 1, fps: Number.NaN }, |
| 131 | + ]) { |
| 132 | + let caught: unknown; |
| 133 | + try { |
| 134 | + validateDistributedDuration(input); |
| 135 | + } catch (err) { |
| 136 | + caught = err; |
| 137 | + } |
| 138 | + expect(caught).toBeInstanceOf(PlanValidationError); |
| 139 | + expect((caught as PlanValidationError).code).toBe(DISTRIBUTED_DURATION_OUT_OF_RANGE); |
| 140 | + } |
| 141 | + }); |
| 142 | +}); |
| 143 | + |
94 | 144 | describe("parseFontFamilyValue", () => { |
95 | 145 | it("splits a comma-separated list and strips whitespace + quotes", () => { |
96 | 146 | expect(parseFontFamilyValue(`"Inter", -apple-system, sans-serif`)).toEqual([ |
|
0 commit comments