@@ -114,13 +114,13 @@ void main() {
114114 print ('' );
115115 print ('=== Strategy Detection ===' );
116116 print (
117- 'URL: \ $ {testUrl.substring(0, testUrl.length > 50 ? 50 : testUrl.length)}...' ,
117+ 'URL: ${testUrl .substring (0 , testUrl .length > 50 ? 50 : testUrl .length )}...' ,
118118 );
119- print ('Detected strategy: \ $ {info.strategy}' );
119+ print ('Detected strategy: ${info .strategy }' );
120120 print (
121- 'File size: \ $ {info.fileSize != null ? "\ $ {info.fileSize! ~/ 1024}KB" : "unknown"}' ,
121+ 'File size: ${info .fileSize != null ? "${info .fileSize ! ~/ 1024 }KB" : "unknown" }' ,
122122 );
123- print ('Range support: \ $ {info.supportsRange}' );
123+ print ('Range support: ${info .supportsRange }' );
124124 print ('' );
125125
126126 // Verify strategy selection logic
@@ -140,8 +140,8 @@ void main() {
140140 } else if (info.supportsRange) {
141141 expect (
142142 info.strategy,
143- equals (ParseStrategy .headerOnly ),
144- reason: 'Medium files with Range should use headerOnly ' ,
143+ equals (ParseStrategy .probe ),
144+ reason: 'Medium files with Range should use probe ' ,
145145 );
146146 } else {
147147 expect (
@@ -181,11 +181,11 @@ void main() {
181181
182182 print ('' );
183183 print ('=== Smart parseUrl ===' );
184- print ('Selected strategy: \ $ selectedStrategy' );
185- print ('Reason: \ $ reason' );
186- print ('Format: \ $ {metadata.format.container}' );
187- print ('Codec: \ $ {metadata.format.codec}' );
188- print ('Duration: \ $ {metadata.format.duration?.toStringAsFixed(2)}s' );
184+ print ('Selected strategy: $selectedStrategy ' );
185+ print ('Reason: $reason ' );
186+ print ('Format: ${metadata .format .container }' );
187+ print ('Codec: ${metadata .format .codec }' );
188+ print ('Duration: ${metadata .format .duration ?.toStringAsFixed (2 )}s' );
189189 print ('' );
190190
191191 expect (selectedStrategy, isNotNull);
@@ -209,8 +209,8 @@ void main() {
209209
210210 print ('' );
211211 print ('=== Full Download Strategy ===' );
212- print ('Format: \ $ {metadata.format.container}' );
213- print ('Codec: \ $ {metadata.format.codec}' );
212+ print ('Format: ${metadata .format .container }' );
213+ print ('Codec: ${metadata .format .codec }' );
214214 print ('' );
215215
216216 expect (metadata.format.container, isNotNull);
@@ -231,8 +231,8 @@ void main() {
231231
232232 print ('' );
233233 print ('=== Header-Only Strategy ===' );
234- print ('Format: \ $ {metadata.format.container}' );
235- print ('Codec: \ $ {metadata.format.codec}' );
234+ print ('Format: ${metadata .format .container }' );
235+ print ('Codec: ${metadata .format .codec }' );
236236 print ('' );
237237
238238 expect (metadata.format.container, isNotNull);
@@ -241,6 +241,28 @@ void main() {
241241 timeout: const Timeout (Duration (seconds: 60 )),
242242 );
243243
244+ test (
245+ 'probe strategy works' ,
246+ () async {
247+ final metadata = await parseUrl (
248+ testUrl,
249+ timeout: const Duration (seconds: 60 ),
250+ strategy: ParseStrategy .probe,
251+ probeStrategy: ProbeStrategy .scatter,
252+ );
253+
254+ print ('' );
255+ print ('=== Probe Strategy ===' );
256+ print ('Format: ${metadata .format .container }' );
257+ print ('Codec: ${metadata .format .codec }' );
258+ print ('' );
259+
260+ expect (metadata.format.container, isNotNull);
261+ },
262+ skip: testUrl.isEmpty ? 'No test URL configured' : false ,
263+ timeout: const Timeout (Duration (seconds: 120 )),
264+ );
265+
244266 test (
245267 'randomAccess strategy works' ,
246268 () async {
@@ -252,8 +274,8 @@ void main() {
252274
253275 print ('' );
254276 print ('=== Random Access Strategy ===' );
255- print ('Format: \ $ {metadata.format.container}' );
256- print ('Codec: \ $ {metadata.format.codec}' );
277+ print ('Format: ${metadata .format .container }' );
278+ print ('Codec: ${metadata .format .codec }' );
257279 print ('' );
258280
259281 expect (metadata.format.container, isNotNull);
@@ -271,8 +293,8 @@ void main() {
271293
272294 print ('' );
273295 print ('=== HttpTokenizer ===' );
274- print ('File size: \ $ {tokenizer.fileInfo?.size} bytes' );
275- print ('Can seek: \ $ {tokenizer.canSeek}' );
296+ print ('File size: ${tokenizer .fileInfo ?.size } bytes' );
297+ print ('Can seek: ${tokenizer .canSeek }' );
276298 print ('' );
277299
278300 expect (tokenizer.fileInfo? .size, greaterThan (0 ));
@@ -295,8 +317,8 @@ void main() {
295317
296318 print ('' );
297319 print ('=== RangeTokenizer ===' );
298- print ('Header size: \ $ {tokenizer.headerSize} bytes' );
299- print ('Total size: \ $ {tokenizer.totalSize} bytes' );
320+ print ('Header size: ${tokenizer .headerSize } bytes' );
321+ print ('Total size: ${tokenizer .totalSize } bytes' );
300322 print ('' );
301323
302324 expect (tokenizer.headerSize, greaterThan (0 ));
@@ -310,15 +332,66 @@ void main() {
310332 timeout: const Timeout (Duration (seconds: 60 )),
311333 );
312334
335+ test (
336+ 'ProbingRangeTokenizer fetches scattered ranges' ,
337+ () async {
338+ final tokenizer = await ProbingRangeTokenizer .fromUrl (
339+ testUrl,
340+ probeStrategy: ProbeStrategy .scatter,
341+ );
342+
343+ print ('' );
344+ print ('=== ProbingRangeTokenizer ===' );
345+ print ('Can seek: ${tokenizer .canSeek }' );
346+ print ('Total size: ${tokenizer .fileInfo ?.size }' );
347+ print ('Fetched: ${tokenizer .fetchedRanges }' );
348+ print ('' );
349+
350+ expect (tokenizer.canSeek, isTrue);
351+ expect (
352+ tokenizer.fetchedRanges['chunks' ],
353+ greaterThan (1 ),
354+ reason: 'Should fetch multiple chunks for scatter strategy' ,
355+ );
356+
357+ tokenizer.close ();
358+ },
359+ skip: testUrl.isEmpty ? 'No test URL configured' : false ,
360+ timeout: const Timeout (Duration (seconds: 60 )),
361+ );
362+
363+ test (
364+ 'ProbingRangeTokenizer with mp4Optimized strategy' ,
365+ () async {
366+ final tokenizer = await ProbingRangeTokenizer .fromUrl (
367+ testUrl,
368+ probeStrategy: ProbeStrategy .mp4Optimized,
369+ );
370+
371+ print ('' );
372+ print ('=== ProbingRangeTokenizer (MP4 Optimized) ===' );
373+ print ('Can seek: ${tokenizer .canSeek }' );
374+ print ('Total size: ${tokenizer .fileInfo ?.size }' );
375+ print ('Fetched: ${tokenizer .fetchedRanges }' );
376+ print ('' );
377+
378+ expect (tokenizer.canSeek, isTrue);
379+
380+ tokenizer.close ();
381+ },
382+ skip: testUrl.isEmpty ? 'No test URL configured' : false ,
383+ timeout: const Timeout (Duration (seconds: 60 )),
384+ );
385+
313386 test (
314387 'RandomAccessTokenizer provides random access' ,
315388 () async {
316389 final tokenizer = await RandomAccessTokenizer .fromUrl (testUrl);
317390
318391 print ('' );
319392 print ('=== RandomAccessTokenizer ===' );
320- print ('Can seek: \ $ {tokenizer.canSeek}' );
321- print ('Total size: \ $ {tokenizer.fileInfo?.size}' );
393+ print ('Can seek: ${tokenizer .canSeek }' );
394+ print ('Total size: ${tokenizer .fileInfo ?.size }' );
322395 print ('' );
323396
324397 expect (tokenizer.canSeek, isTrue);
0 commit comments