@bernierllc/content-type-audio 1.2.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AudioContentTypeManager.js +1 -0
- package/dist/AudioContentTypeManager.js.map +1 -1
- package/dist/errors.d.ts +12 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +25 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
- package/.eslintrc.js +0 -42
- package/CHANGELOG.md +0 -64
- package/__tests__/AudioContentTypeManager.test.ts +0 -592
- package/__tests__/integration.test.ts +0 -279
- package/__tests__/utils.test.ts +0 -142
- package/jest.config.cjs +0 -32
- package/src/AudioContentTypeManager.ts +0 -238
- package/src/index.ts +0 -31
- package/src/schemas.ts +0 -42
- package/src/types.ts +0 -82
- package/src/utils.ts +0 -80
- package/tsconfig.json +0 -19
|
@@ -1,592 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Copyright (c) 2025 Bernier LLC
|
|
3
|
-
|
|
4
|
-
This file is licensed to the client under a limited-use license.
|
|
5
|
-
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
6
|
-
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { AudioContentTypeManager, validateAudio } from '../src/AudioContentTypeManager';
|
|
10
|
-
import { AudioFormat, AudioContentType, AudioMetadata } from '../src/types';
|
|
11
|
-
import { ContentTypeRegistry } from '@bernierllc/content-type-registry';
|
|
12
|
-
|
|
13
|
-
describe('AudioContentTypeManager', () => {
|
|
14
|
-
let manager: AudioContentTypeManager;
|
|
15
|
-
|
|
16
|
-
beforeEach(() => {
|
|
17
|
-
manager = new AudioContentTypeManager({
|
|
18
|
-
maxFileSize: 50 * 1024 * 1024, // 50MB
|
|
19
|
-
allowedFormats: [AudioFormat.MP3, AudioFormat.WAV],
|
|
20
|
-
requireMetadata: true
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe('constructor', () => {
|
|
25
|
-
it('should create manager with default config', () => {
|
|
26
|
-
const defaultManager = new AudioContentTypeManager();
|
|
27
|
-
expect(defaultManager).toBeDefined();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should create manager with custom config', () => {
|
|
31
|
-
const customManager = new AudioContentTypeManager({
|
|
32
|
-
maxFileSize: 10 * 1024 * 1024,
|
|
33
|
-
allowedFormats: [AudioFormat.MP3],
|
|
34
|
-
requireMetadata: false
|
|
35
|
-
});
|
|
36
|
-
expect(customManager).toBeDefined();
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should merge custom config with defaults', () => {
|
|
40
|
-
const partialManager = new AudioContentTypeManager({
|
|
41
|
-
maxFileSize: 20 * 1024 * 1024
|
|
42
|
-
});
|
|
43
|
-
expect(partialManager).toBeDefined();
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
describe('register', () => {
|
|
48
|
-
it('should register audio content type with registry', () => {
|
|
49
|
-
const registry = new ContentTypeRegistry();
|
|
50
|
-
manager.register(registry);
|
|
51
|
-
|
|
52
|
-
const result = registry.get('audio');
|
|
53
|
-
expect(result.success).toBe(true);
|
|
54
|
-
expect(result.data).toBeDefined();
|
|
55
|
-
expect(result.data?.name).toBe('Audio');
|
|
56
|
-
expect(result.data?.baseType).toBe('audio');
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('should include editor configuration', () => {
|
|
60
|
-
const registry = new ContentTypeRegistry();
|
|
61
|
-
manager.register(registry);
|
|
62
|
-
|
|
63
|
-
const result = registry.get('audio');
|
|
64
|
-
expect(result.success).toBe(true);
|
|
65
|
-
expect(result.data?.editor).toBeDefined();
|
|
66
|
-
expect(result.data?.editor.component).toBe('file-upload-with-player');
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should include storage and publishing configuration', () => {
|
|
70
|
-
const registry = new ContentTypeRegistry();
|
|
71
|
-
manager.register(registry);
|
|
72
|
-
|
|
73
|
-
const result = registry.get('audio');
|
|
74
|
-
expect(result.success).toBe(true);
|
|
75
|
-
expect(result.data?.storage).toBeDefined();
|
|
76
|
-
expect(result.data?.publishing).toBeDefined();
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
describe('getSchema', () => {
|
|
81
|
-
it('should return Zod schema', () => {
|
|
82
|
-
const schema = manager.getSchema();
|
|
83
|
-
expect(schema).toBeDefined();
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
describe('validate', () => {
|
|
88
|
-
it('should validate correct audio content', async () => {
|
|
89
|
-
const content: AudioContentType = {
|
|
90
|
-
id: 'audio_123',
|
|
91
|
-
type: 'audio',
|
|
92
|
-
metadata: {
|
|
93
|
-
filename: 'song.mp3',
|
|
94
|
-
mimeType: AudioFormat.MP3,
|
|
95
|
-
size: 5 * 1024 * 1024, // 5MB
|
|
96
|
-
duration: 180, // 3 minutes
|
|
97
|
-
bitrate: 192,
|
|
98
|
-
title: 'Test Song'
|
|
99
|
-
},
|
|
100
|
-
createdAt: new Date(),
|
|
101
|
-
updatedAt: new Date()
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
const result = manager.validate(content);
|
|
105
|
-
|
|
106
|
-
expect(result.valid).toBe(true);
|
|
107
|
-
expect(result.errors).toBeUndefined();
|
|
108
|
-
expect(result.metadata?.title).toBe('Test Song');
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('should reject audio exceeding max file size', async () => {
|
|
112
|
-
const content: AudioContentType = {
|
|
113
|
-
id: 'audio_456',
|
|
114
|
-
type: 'audio',
|
|
115
|
-
metadata: {
|
|
116
|
-
filename: 'large.mp3',
|
|
117
|
-
mimeType: AudioFormat.MP3,
|
|
118
|
-
size: 100 * 1024 * 1024, // 100MB (exceeds 50MB limit)
|
|
119
|
-
duration: 3600,
|
|
120
|
-
bitrate: 192,
|
|
121
|
-
title: 'Large File'
|
|
122
|
-
},
|
|
123
|
-
createdAt: new Date(),
|
|
124
|
-
updatedAt: new Date()
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const result = manager.validate(content);
|
|
128
|
-
|
|
129
|
-
expect(result.valid).toBe(false);
|
|
130
|
-
expect(result.errors).toBeDefined();
|
|
131
|
-
expect(result.errors?.[0]).toContain('exceeds maximum');
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('should reject disallowed audio formats', async () => {
|
|
135
|
-
const content: AudioContentType = {
|
|
136
|
-
id: 'audio_789',
|
|
137
|
-
type: 'audio',
|
|
138
|
-
metadata: {
|
|
139
|
-
filename: 'song.flac',
|
|
140
|
-
mimeType: AudioFormat.FLAC, // Not in allowedFormats
|
|
141
|
-
size: 1024 * 1024,
|
|
142
|
-
duration: 60,
|
|
143
|
-
bitrate: 128,
|
|
144
|
-
title: 'Test Song'
|
|
145
|
-
},
|
|
146
|
-
createdAt: new Date(),
|
|
147
|
-
updatedAt: new Date()
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const result = manager.validate(content);
|
|
151
|
-
|
|
152
|
-
expect(result.valid).toBe(false);
|
|
153
|
-
expect(result.errors).toBeDefined();
|
|
154
|
-
expect(result.errors?.[0]).toContain('not allowed');
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('should require title when requireMetadata is true', async () => {
|
|
158
|
-
const content: AudioContentType = {
|
|
159
|
-
id: 'audio_101',
|
|
160
|
-
type: 'audio',
|
|
161
|
-
metadata: {
|
|
162
|
-
filename: 'song.mp3',
|
|
163
|
-
mimeType: AudioFormat.MP3,
|
|
164
|
-
size: 1024 * 1024,
|
|
165
|
-
duration: 60,
|
|
166
|
-
bitrate: 128
|
|
167
|
-
// No title
|
|
168
|
-
},
|
|
169
|
-
createdAt: new Date(),
|
|
170
|
-
updatedAt: new Date()
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
const result = manager.validate(content);
|
|
174
|
-
|
|
175
|
-
expect(result.valid).toBe(false);
|
|
176
|
-
expect(result.errors).toBeDefined();
|
|
177
|
-
expect(result.errors?.[0]).toContain('Title is required');
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('should handle invalid content structure', async () => {
|
|
181
|
-
const invalidContent = {
|
|
182
|
-
id: 'audio_999',
|
|
183
|
-
type: 'video', // Wrong type
|
|
184
|
-
metadata: {}
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
const result = manager.validate(invalidContent);
|
|
188
|
-
|
|
189
|
-
expect(result.valid).toBe(false);
|
|
190
|
-
expect(result.errors).toBeDefined();
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('should handle missing required fields', async () => {
|
|
194
|
-
const incompleteContent = {
|
|
195
|
-
id: 'audio_888',
|
|
196
|
-
type: 'audio'
|
|
197
|
-
// Missing metadata
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
const result = manager.validate(incompleteContent);
|
|
201
|
-
|
|
202
|
-
expect(result.valid).toBe(false);
|
|
203
|
-
expect(result.errors).toBeDefined();
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
it('should validate optional fields', async () => {
|
|
207
|
-
const content: AudioContentType = {
|
|
208
|
-
id: 'audio_777',
|
|
209
|
-
type: 'audio',
|
|
210
|
-
metadata: {
|
|
211
|
-
filename: 'song.mp3',
|
|
212
|
-
mimeType: AudioFormat.MP3,
|
|
213
|
-
size: 1024 * 1024,
|
|
214
|
-
duration: 60,
|
|
215
|
-
bitrate: 128,
|
|
216
|
-
title: 'Test Song',
|
|
217
|
-
artist: 'Test Artist',
|
|
218
|
-
album: 'Test Album',
|
|
219
|
-
year: 2024,
|
|
220
|
-
sampleRate: 44100,
|
|
221
|
-
channels: 2
|
|
222
|
-
},
|
|
223
|
-
filePath: '/path/to/song.mp3',
|
|
224
|
-
createdAt: new Date(),
|
|
225
|
-
updatedAt: new Date()
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
const result = manager.validate(content);
|
|
229
|
-
|
|
230
|
-
expect(result.valid).toBe(true);
|
|
231
|
-
expect(result.metadata?.artist).toBe('Test Artist');
|
|
232
|
-
expect(result.metadata?.album).toBe('Test Album');
|
|
233
|
-
expect(result.metadata?.year).toBe(2024);
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
it('should reject negative duration', async () => {
|
|
237
|
-
const content: AudioContentType = {
|
|
238
|
-
id: 'audio_666',
|
|
239
|
-
type: 'audio',
|
|
240
|
-
metadata: {
|
|
241
|
-
filename: 'song.mp3',
|
|
242
|
-
mimeType: AudioFormat.MP3,
|
|
243
|
-
size: 1024 * 1024,
|
|
244
|
-
duration: -10, // Invalid
|
|
245
|
-
bitrate: 128,
|
|
246
|
-
title: 'Test Song'
|
|
247
|
-
},
|
|
248
|
-
createdAt: new Date(),
|
|
249
|
-
updatedAt: new Date()
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
const result = manager.validate(content);
|
|
253
|
-
|
|
254
|
-
expect(result.valid).toBe(false);
|
|
255
|
-
expect(result.errors).toBeDefined();
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
it('should reject negative bitrate', async () => {
|
|
259
|
-
const content: AudioContentType = {
|
|
260
|
-
id: 'audio_555',
|
|
261
|
-
type: 'audio',
|
|
262
|
-
metadata: {
|
|
263
|
-
filename: 'song.mp3',
|
|
264
|
-
mimeType: AudioFormat.MP3,
|
|
265
|
-
size: 1024 * 1024,
|
|
266
|
-
duration: 60,
|
|
267
|
-
bitrate: -128, // Invalid
|
|
268
|
-
title: 'Test Song'
|
|
269
|
-
},
|
|
270
|
-
createdAt: new Date(),
|
|
271
|
-
updatedAt: new Date()
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
const result = manager.validate(content);
|
|
275
|
-
|
|
276
|
-
expect(result.valid).toBe(false);
|
|
277
|
-
expect(result.errors).toBeDefined();
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
it('should reject invalid year range', () => {
|
|
281
|
-
const content: AudioContentType = {
|
|
282
|
-
id: 'audio_444',
|
|
283
|
-
type: 'audio',
|
|
284
|
-
metadata: {
|
|
285
|
-
filename: 'song.mp3',
|
|
286
|
-
mimeType: AudioFormat.MP3,
|
|
287
|
-
size: 1024 * 1024,
|
|
288
|
-
duration: 60,
|
|
289
|
-
bitrate: 128,
|
|
290
|
-
title: 'Test Song',
|
|
291
|
-
year: 3000 // Too far in future
|
|
292
|
-
},
|
|
293
|
-
createdAt: new Date(),
|
|
294
|
-
updatedAt: new Date()
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
const result = manager.validate(content);
|
|
298
|
-
|
|
299
|
-
expect(result.valid).toBe(false);
|
|
300
|
-
expect(result.errors).toBeDefined();
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
it('should handle validation with allowed formats config', () => {
|
|
304
|
-
const manager = new AudioContentTypeManager({
|
|
305
|
-
allowedFormats: [AudioFormat.MP3, AudioFormat.WAV]
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
const content: AudioContentType = {
|
|
309
|
-
id: 'audio_333',
|
|
310
|
-
type: 'audio',
|
|
311
|
-
metadata: {
|
|
312
|
-
filename: 'song.mp3',
|
|
313
|
-
mimeType: AudioFormat.MP3,
|
|
314
|
-
size: 1024 * 1024,
|
|
315
|
-
duration: 60,
|
|
316
|
-
bitrate: 128
|
|
317
|
-
},
|
|
318
|
-
createdAt: new Date(),
|
|
319
|
-
updatedAt: new Date()
|
|
320
|
-
};
|
|
321
|
-
|
|
322
|
-
const result = manager.validate(content);
|
|
323
|
-
expect(result.valid).toBe(true);
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
it('should handle validation without maxFileSize config', () => {
|
|
327
|
-
const manager = new AudioContentTypeManager({
|
|
328
|
-
maxFileSize: undefined
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
const content: AudioContentType = {
|
|
332
|
-
id: 'audio_222',
|
|
333
|
-
type: 'audio',
|
|
334
|
-
metadata: {
|
|
335
|
-
filename: 'huge.mp3',
|
|
336
|
-
mimeType: AudioFormat.MP3,
|
|
337
|
-
size: 500 * 1024 * 1024, // 500MB
|
|
338
|
-
duration: 3600,
|
|
339
|
-
bitrate: 320
|
|
340
|
-
},
|
|
341
|
-
createdAt: new Date(),
|
|
342
|
-
updatedAt: new Date()
|
|
343
|
-
};
|
|
344
|
-
|
|
345
|
-
const result = manager.validate(content);
|
|
346
|
-
expect(result.valid).toBe(true);
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
it('should handle validation without allowedFormats config', () => {
|
|
350
|
-
const manager = new AudioContentTypeManager({
|
|
351
|
-
allowedFormats: undefined
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
const content: AudioContentType = {
|
|
355
|
-
id: 'audio_111',
|
|
356
|
-
type: 'audio',
|
|
357
|
-
metadata: {
|
|
358
|
-
filename: 'song.flac',
|
|
359
|
-
mimeType: AudioFormat.FLAC,
|
|
360
|
-
size: 1024 * 1024,
|
|
361
|
-
duration: 60,
|
|
362
|
-
bitrate: 1411
|
|
363
|
-
},
|
|
364
|
-
createdAt: new Date(),
|
|
365
|
-
updatedAt: new Date()
|
|
366
|
-
};
|
|
367
|
-
|
|
368
|
-
const result = manager.validate(content);
|
|
369
|
-
expect(result.valid).toBe(true);
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
it('should handle validation catching non-Zod errors', () => {
|
|
373
|
-
const manager = new AudioContentTypeManager();
|
|
374
|
-
|
|
375
|
-
// Trigger an error by passing something that causes a non-ZodError
|
|
376
|
-
const result = manager.validate(undefined);
|
|
377
|
-
|
|
378
|
-
expect(result.valid).toBe(false);
|
|
379
|
-
expect(result.errors).toBeDefined();
|
|
380
|
-
});
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
describe('create', () => {
|
|
384
|
-
it('should create audio content with metadata', () => {
|
|
385
|
-
const metadata: AudioMetadata = {
|
|
386
|
-
filename: 'test.mp3',
|
|
387
|
-
mimeType: AudioFormat.MP3,
|
|
388
|
-
size: 1024 * 1024,
|
|
389
|
-
duration: 60,
|
|
390
|
-
bitrate: 128,
|
|
391
|
-
title: 'Test Audio'
|
|
392
|
-
};
|
|
393
|
-
|
|
394
|
-
const content = manager.create(metadata, {
|
|
395
|
-
filePath: '/path/to/test.mp3',
|
|
396
|
-
streamingUrl: 'https://cdn.example.com/test.mp3'
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
expect(content.type).toBe('audio');
|
|
400
|
-
expect(content.metadata.title).toBe('Test Audio');
|
|
401
|
-
expect(content.filePath).toBe('/path/to/test.mp3');
|
|
402
|
-
expect(content.streamingUrl).toBe('https://cdn.example.com/test.mp3');
|
|
403
|
-
expect(content.id).toMatch(/^audio_/);
|
|
404
|
-
expect(content.createdAt).toBeInstanceOf(Date);
|
|
405
|
-
expect(content.updatedAt).toBeInstanceOf(Date);
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
it('should create audio content without optional fields', () => {
|
|
409
|
-
const metadata: AudioMetadata = {
|
|
410
|
-
filename: 'test.mp3',
|
|
411
|
-
mimeType: AudioFormat.MP3,
|
|
412
|
-
size: 1024 * 1024,
|
|
413
|
-
duration: 60,
|
|
414
|
-
bitrate: 128
|
|
415
|
-
};
|
|
416
|
-
|
|
417
|
-
const content = manager.create(metadata);
|
|
418
|
-
|
|
419
|
-
expect(content.type).toBe('audio');
|
|
420
|
-
expect(content.filePath).toBeUndefined();
|
|
421
|
-
expect(content.fileUrl).toBeUndefined();
|
|
422
|
-
expect(content.streamingUrl).toBeUndefined();
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
it('should generate unique IDs', () => {
|
|
426
|
-
const metadata: AudioMetadata = {
|
|
427
|
-
filename: 'test.mp3',
|
|
428
|
-
mimeType: AudioFormat.MP3,
|
|
429
|
-
size: 1024 * 1024,
|
|
430
|
-
duration: 60,
|
|
431
|
-
bitrate: 128
|
|
432
|
-
};
|
|
433
|
-
|
|
434
|
-
const content1 = manager.create(metadata);
|
|
435
|
-
const content2 = manager.create(metadata);
|
|
436
|
-
|
|
437
|
-
expect(content1.id).not.toBe(content2.id);
|
|
438
|
-
});
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
describe('utility methods', () => {
|
|
442
|
-
it('should parse duration', () => {
|
|
443
|
-
expect(manager.parseDuration('1:23:45')).toBe(5025);
|
|
444
|
-
expect(manager.parseDuration('23:45')).toBe(1425);
|
|
445
|
-
expect(manager.parseDuration('123')).toBe(123);
|
|
446
|
-
expect(manager.parseDuration(180)).toBe(180);
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
it('should format duration', () => {
|
|
450
|
-
expect(manager.formatDuration(5025)).toBe('1:23:45');
|
|
451
|
-
expect(manager.formatDuration(1425)).toBe('23:45');
|
|
452
|
-
expect(manager.formatDuration(45)).toBe('0:45');
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
it('should calculate bitrate', () => {
|
|
456
|
-
const fileSize = 5 * 1024 * 1024;
|
|
457
|
-
const duration = 180;
|
|
458
|
-
const bitrate = manager.calculateBitrate(fileSize, duration);
|
|
459
|
-
|
|
460
|
-
expect(bitrate).toBeGreaterThan(0);
|
|
461
|
-
expect(bitrate).toBeCloseTo(233, 0);
|
|
462
|
-
});
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
describe('validateAudio wrapper', () => {
|
|
466
|
-
it('should return success result for valid content', () => {
|
|
467
|
-
const content: AudioContentType = {
|
|
468
|
-
id: 'audio_123',
|
|
469
|
-
type: 'audio',
|
|
470
|
-
metadata: {
|
|
471
|
-
filename: 'song.mp3',
|
|
472
|
-
mimeType: AudioFormat.MP3,
|
|
473
|
-
size: 5 * 1024 * 1024,
|
|
474
|
-
duration: 180,
|
|
475
|
-
bitrate: 192,
|
|
476
|
-
title: 'Test Song'
|
|
477
|
-
},
|
|
478
|
-
createdAt: new Date(),
|
|
479
|
-
updatedAt: new Date()
|
|
480
|
-
};
|
|
481
|
-
|
|
482
|
-
const result = validateAudio(manager, content);
|
|
483
|
-
|
|
484
|
-
expect(result.success).toBe(true);
|
|
485
|
-
expect(result.data).toBeDefined();
|
|
486
|
-
expect(result.data?.valid).toBe(true);
|
|
487
|
-
expect(result.error).toBeUndefined();
|
|
488
|
-
});
|
|
489
|
-
|
|
490
|
-
it('should return error result for invalid content with error message', () => {
|
|
491
|
-
const invalidContent = {
|
|
492
|
-
id: 'audio_999',
|
|
493
|
-
type: 'invalid'
|
|
494
|
-
};
|
|
495
|
-
|
|
496
|
-
const result = validateAudio(manager, invalidContent);
|
|
497
|
-
|
|
498
|
-
expect(result.success).toBe(false);
|
|
499
|
-
expect(result.data).toBeDefined();
|
|
500
|
-
expect(result.data?.valid).toBe(false);
|
|
501
|
-
expect(result.error).toBeDefined();
|
|
502
|
-
expect(result.error).toContain('type');
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
it('should return error result for content with validation errors but no error array', () => {
|
|
506
|
-
const strictManager = new AudioContentTypeManager({
|
|
507
|
-
maxFileSize: 1024,
|
|
508
|
-
requireMetadata: true
|
|
509
|
-
});
|
|
510
|
-
|
|
511
|
-
const content = strictManager.create({
|
|
512
|
-
filename: 'test.mp3',
|
|
513
|
-
mimeType: AudioFormat.MP3,
|
|
514
|
-
size: 2048, // Exceeds limit
|
|
515
|
-
duration: 60,
|
|
516
|
-
bitrate: 128
|
|
517
|
-
// Missing title
|
|
518
|
-
});
|
|
519
|
-
|
|
520
|
-
const result = validateAudio(strictManager, content);
|
|
521
|
-
|
|
522
|
-
expect(result.success).toBe(false);
|
|
523
|
-
expect(result.data).toBeDefined();
|
|
524
|
-
expect(result.data?.valid).toBe(false);
|
|
525
|
-
});
|
|
526
|
-
|
|
527
|
-
it('should handle exceptions gracefully', () => {
|
|
528
|
-
const result = validateAudio(manager, null);
|
|
529
|
-
|
|
530
|
-
expect(result.success).toBe(false);
|
|
531
|
-
expect(result.error).toBeDefined();
|
|
532
|
-
});
|
|
533
|
-
});
|
|
534
|
-
|
|
535
|
-
describe('edge cases', () => {
|
|
536
|
-
it('should handle empty strings in parseDuration', () => {
|
|
537
|
-
expect(manager.parseDuration('')).toBe(0);
|
|
538
|
-
});
|
|
539
|
-
|
|
540
|
-
it('should handle zero bitrate calculation', () => {
|
|
541
|
-
expect(manager.calculateBitrate(1024, 0)).toBe(0);
|
|
542
|
-
});
|
|
543
|
-
|
|
544
|
-
it('should format zero duration', () => {
|
|
545
|
-
expect(manager.formatDuration(0)).toBe('0:00');
|
|
546
|
-
});
|
|
547
|
-
|
|
548
|
-
it('should validate content with no optional URLs', () => {
|
|
549
|
-
const manager = new AudioContentTypeManager();
|
|
550
|
-
const content = manager.create({
|
|
551
|
-
filename: 'test.mp3',
|
|
552
|
-
mimeType: AudioFormat.MP3,
|
|
553
|
-
size: 1024 * 1024,
|
|
554
|
-
duration: 60,
|
|
555
|
-
bitrate: 128
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
expect(content.filePath).toBeUndefined();
|
|
559
|
-
expect(content.fileUrl).toBeUndefined();
|
|
560
|
-
expect(content.streamingUrl).toBeUndefined();
|
|
561
|
-
});
|
|
562
|
-
|
|
563
|
-
it('should validate content with all optional fields', () => {
|
|
564
|
-
const manager = new AudioContentTypeManager();
|
|
565
|
-
const content = manager.create(
|
|
566
|
-
{
|
|
567
|
-
filename: 'test.mp3',
|
|
568
|
-
mimeType: AudioFormat.MP3,
|
|
569
|
-
size: 1024 * 1024,
|
|
570
|
-
duration: 60,
|
|
571
|
-
bitrate: 128,
|
|
572
|
-
sampleRate: 44100,
|
|
573
|
-
channels: 2,
|
|
574
|
-
title: 'Test',
|
|
575
|
-
artist: 'Artist',
|
|
576
|
-
album: 'Album',
|
|
577
|
-
year: 2024,
|
|
578
|
-
coverArt: 'https://example.com/cover.jpg'
|
|
579
|
-
},
|
|
580
|
-
{
|
|
581
|
-
filePath: '/path/to/file',
|
|
582
|
-
fileUrl: 'https://example.com/file',
|
|
583
|
-
streamingUrl: 'https://stream.example.com/file'
|
|
584
|
-
}
|
|
585
|
-
);
|
|
586
|
-
|
|
587
|
-
expect(content.filePath).toBe('/path/to/file');
|
|
588
|
-
expect(content.fileUrl).toBe('https://example.com/file');
|
|
589
|
-
expect(content.streamingUrl).toBe('https://stream.example.com/file');
|
|
590
|
-
});
|
|
591
|
-
});
|
|
592
|
-
});
|