@@ -17,11 +17,16 @@ const _shortLine = 'Short line.';
1717const _indentedLongLine = ' This is an indented long line that needs to be '
1818 'wrapped and indentation preserved.' ;
1919const _ansiReset = 'This is normal text. \x 1B[0m<- Reset point.' ;
20- const _ansiBoldTextSpecificReset = 'This is normal, \x 1B[1mthis is bold\x 1B[22m, and this uses specific reset.' ;
21- const _ansiMixedStyles = 'Normal, \x 1B[31mRed\x 1B[0m, \x 1B[1mBold\x 1B[0m, \x 1B[4mUnderline\x 1B[0m, \x 1B[1;34mBold Blue\x 1B[0m, Normal again.' ;
22- const _ansiLongSequence = 'Start \x 1B[1;3;4;5;7;9;31;42;38;5;196;48;5;226m Beaucoup formatting! \x 1B[0m End' ;
23- const _ansiCombined256 = '\x 1B[1;38;5;27;48;5;220mBold Bright Blue FG (27) on Gold BG (220)\x 1B[0m' ;
24- const _ansiCombinedTrueColor = '\x 1B[4;48;2;50;50;50;38;2;150;250;150mUnderlined Light Green FG on Dark Grey BG\x 1B[0m' ;
20+ const _ansiBoldTextSpecificReset =
21+ 'This is normal, \x 1B[1mthis is bold\x 1B[22m, and this uses specific reset.' ;
22+ const _ansiMixedStyles =
23+ 'Normal, \x 1B[31mRed\x 1B[0m, \x 1B[1mBold\x 1B[0m, \x 1B[4mUnderline\x 1B[0m, \x 1B[1;34mBold Blue\x 1B[0m, Normal again.' ;
24+ const _ansiLongSequence =
25+ 'Start \x 1B[1;3;4;5;7;9;31;42;38;5;196;48;5;226m Beaucoup formatting! \x 1B[0m End' ;
26+ const _ansiCombined256 =
27+ '\x 1B[1;38;5;27;48;5;220mBold Bright Blue FG (27) on Gold BG (220)\x 1B[0m' ;
28+ const _ansiCombinedTrueColor =
29+ '\x 1B[4;48;2;50;50;50;38;2;150;250;150mUnderlined Light Green FG on Dark Grey BG\x 1B[0m' ;
2530
2631void main () {
2732 group ('padding' , () {
@@ -224,60 +229,77 @@ needs to be wrapped.
224229 test ('lengthWithoutAnsi returns correct length on lines without ansi' , () {
225230 expect (_longLine.lengthWithoutAnsi, equals (_longLine.length));
226231 });
227- test ('lengthWithoutAnsi returns correct length on lines newlines and without ansi' , () {
228- expect (_longLineWithNewlines.lengthWithoutAnsi, equals (_longLineWithNewlines.length));
232+ test (
233+ 'lengthWithoutAnsi returns correct length on lines newlines and without ansi' ,
234+ () {
235+ expect (_longLineWithNewlines.lengthWithoutAnsi,
236+ equals (_longLineWithNewlines.length));
237+ });
238+ test (
239+ 'lengthWithoutAnsi returns correct length on lines indented/newlines and without ansi' ,
240+ () {
241+ expect (_indentedLongLineWithNewlines.lengthWithoutAnsi,
242+ equals (_indentedLongLineWithNewlines.length));
229243 });
230- test ('lengthWithoutAnsi returns correct length on lines indented/newlines and without ansi' , () {
231- expect (_indentedLongLineWithNewlines.lengthWithoutAnsi, equals (_indentedLongLineWithNewlines.length));
232- });
233- test ('lengthWithoutAnsi returns correct length on short line without ansi' , () {
244+ test ('lengthWithoutAnsi returns correct length on short line without ansi' ,
245+ () {
234246 expect (_shortLine.lengthWithoutAnsi, equals (_shortLine.length));
235- });
247+ });
236248 });
237249
238250 group ('lengthWithoutAnsi is correct with no ANSI sequences' , () {
239251 test ('lengthWithoutAnsi returns correct length on lines without ansi' , () {
240252 expect (_longLine.lengthWithoutAnsi, equals (_longLine.length));
241253 });
242- test ('lengthWithoutAnsi returns correct length on lines newlines and without ansi' , () {
243- expect (_longLineWithNewlines.lengthWithoutAnsi, equals (_longLineWithNewlines.length));
254+ test (
255+ 'lengthWithoutAnsi returns correct length on lines newlines and without ansi' ,
256+ () {
257+ expect (_longLineWithNewlines.lengthWithoutAnsi,
258+ equals (_longLineWithNewlines.length));
259+ });
260+ test (
261+ 'lengthWithoutAnsi returns correct length on lines indented/newlines and without ansi' ,
262+ () {
263+ expect (_indentedLongLineWithNewlines.lengthWithoutAnsi,
264+ equals (_indentedLongLineWithNewlines.length));
244265 });
245- test ('lengthWithoutAnsi returns correct length on lines indented/newlines and without ansi' , () {
246- expect (_indentedLongLineWithNewlines.lengthWithoutAnsi, equals (_indentedLongLineWithNewlines.length));
247- });
248- test ('lengthWithoutAnsi returns correct length on short line without ansi' , () {
266+ test ('lengthWithoutAnsi returns correct length on short line without ansi' ,
267+ () {
249268 expect (_shortLine.lengthWithoutAnsi, equals (_shortLine.length));
250- });
269+ });
251270 });
252271
253272 group ('lengthWithoutAnsi is correct with variety of ANSI sequences' , () {
254273 test ('lengthWithoutAnsi returns correct length - ansi reset' , () {
255274 expect (_ansiReset.lengthWithoutAnsi, equals (36 ));
256275 });
257- test ('lengthWithoutAnsi returns correct length - ansi bold, bold specific reset' , () {
276+ test (
277+ 'lengthWithoutAnsi returns correct length - ansi bold, bold specific reset' ,
278+ () {
258279 expect (_ansiBoldTextSpecificReset.lengthWithoutAnsi, equals (59 ));
259280 });
260281 test ('lengthWithoutAnsi returns correct length - ansi mixed styles' , () {
261282 expect (_ansiMixedStyles.lengthWithoutAnsi, equals (54 ));
262- });
283+ });
263284 test ('lengthWithoutAnsi returns correct length- ansi long sequence' , () {
264285 expect (_ansiLongSequence.lengthWithoutAnsi, equals (32 ));
265- });
266- test ('lengthWithoutAnsi returns correct length - ansi 256 color sequence' , () {
286+ });
287+ test ('lengthWithoutAnsi returns correct length - ansi 256 color sequence' ,
288+ () {
267289 expect (_ansiCombined256.lengthWithoutAnsi, equals (41 ));
268- });
269- test ('lengthWithoutAnsi returns correct length - ansi true color sequences' , () {
290+ });
291+ test ('lengthWithoutAnsi returns correct length - ansi true color sequences' ,
292+ () {
270293 expect (_ansiCombinedTrueColor.lengthWithoutAnsi, equals (41 ));
271294 });
272295 });
273296
274297 group ('ANSI RegExp Systematic Tests' , () {
275-
276298 test ('Identifies standard SGR (Select Graphic Rendition) codes' , () {
277299 const reset = '\x 1b[0m' ;
278300 const boldRed = '\x 1b[1;31m' ;
279301 const bgBlue = '\x 1b[44m' ;
280-
302+
281303 expect (reset.ansiLength, equals (4 ));
282304 expect (boldRed.ansiLength, equals (7 ));
283305 expect (bgBlue.ansiLength, equals (5 ));
@@ -286,7 +308,7 @@ needs to be wrapped.
286308 test ('Identifies Private Mode sequences (starting with ?)' , () {
287309 const hideCursor = '\x 1b[?25l' ;
288310 const showCursor = '\x 1b[?25h' ;
289-
311+
290312 expect (hideCursor.ansiLength, equals (6 ));
291313 expect (showCursor.ansiLength, equals (6 ));
292314 });
@@ -296,35 +318,37 @@ needs to be wrapped.
296318 // We check all standard alphabetic termination characters.
297319 for (int i = 0x40 ; i <= 0x7E ; i++ ) {
298320 if (i > 90 && i < 97 ) continue ; // Skip non-alphas like [ \ ] ^ _ `
299-
321+
300322 final char = String .fromCharCode (i);
301323 final sequence = '\x 1b[1;2;3$char ' ;
302-
324+
303325 // The RegExp should match the entire string
304- expect (sequence.ansiLength, equals (sequence.length),
305- reason: 'Failed on character: $char (ASCII $i )' );
326+ expect (sequence.ansiLength, equals (sequence.length),
327+ reason: 'Failed on character: $char (ASCII $i )' );
306328 }
307329 });
308330
309- test ('Correctly calculates length in mixed strings and withoutAnsi getter' , () {
331+ test ('Correctly calculates length in mixed strings and withoutAnsi getter' ,
332+ () {
310333 const text = 'Hello \x 1b[32mWorld\x 1b[0m' ;
311- const textWithoutAnsi = 'Hello World' ; // Expectation.
312-
334+ const textWithoutAnsi = 'Hello World' ; // Expectation.
335+
313336 expect (text.ansiLength, equals (text.length - textWithoutAnsi.length));
314337 expect (text.lengthWithoutAnsi, textWithoutAnsi.length);
315338 expect (text.withoutAnsi, textWithoutAnsi);
316339 expect (text.length, equals (20 ));
317340 });
318341
319342 test ('Handles semicolon separators' , () {
320- const semiColonSeparators = '\x 1b[38;5;209;48;5;255m' ; // Extended 256-color sequence
343+ const semiColonSeparators =
344+ '\x 1b[38;5;209;48;5;255m' ; // Extended 256-color sequence
321345 expect (semiColonSeparators.ansiLength, equals (20 ));
322346 });
323347
324348 test ('Does not match partial or broken sequences' , () {
325349 const broken = ' \x 1b[31' ; // Missing the terminator 'm'
326350 expect (broken.ansiLength, equals (0 ));
327-
351+
328352 const justEsc = '\x 1b' ;
329353 expect (justEsc.ansiLength, equals (0 ));
330354 });
@@ -355,9 +379,9 @@ needs to be wrapped.
355379 ];
356380
357381 for (var testCase in cases) {
358- expect (testCase.lengthWithoutAnsi + testCase.ansiLength,
359- equals (testCase.length),
360- reason: 'Failed sum check for: $testCase ' );
382+ expect (testCase.lengthWithoutAnsi + testCase.ansiLength,
383+ equals (testCase.length),
384+ reason: 'Failed sum check for: $testCase ' );
361385 }
362386 });
363387 });
@@ -367,12 +391,12 @@ needs to be wrapped.
367391 // "Red" is 3 visual chars, but 12 literal chars
368392 // \x1B[31mRed\x1B[0m
369393 const red = '\x 1B[31mRed\x 1B[0m' ;
370-
371- // We want a visual width of 10.
394+
395+ // We want a visual width of 10.
372396 // Traditional padRight(10) would see 12 chars and add nothing.
373397 // Our string extension padRightIgnoreAnsi should add 7 spaces (10 - 3 visual).
374398 final padded = red.padRightIgnoreAnsi (10 );
375-
399+
376400 expect (padded.lengthWithoutAnsi, equals (10 ));
377401 expect (padded.startsWith (red), isTrue);
378402 expect (padded.endsWith (' ' * 7 ), isTrue);
@@ -399,21 +423,20 @@ needs to be wrapped.
399423 });
400424
401425 group ('Advanced ANSI/ECMA-48 RegExp Tests' , () {
402-
403426 test ('Matches sequences with Intermediate Bytes correctly' , () {
404427 // CSI 1 Space q (Set cursor style)
405428 // Here, the space is an Intermediate Byte (\x20)
406- const setCursorStyle = '\x 1b[1 q' ;
429+ const setCursorStyle = '\x 1b[1 q' ;
407430 expect (setCursorStyle.ansiLength, equals (5 ));
408431 expect (setCursorStyle.withoutAnsi, equals ('' ));
409432 });
410433
411434 test ('Ensures it does NOT match sequences that violate the order' , () {
412435 // The standard requires: Parameters (0-9:;<=>?) THEN Intermediates (Space!"#$%&'()*+,-./) THEN Final (@-~)
413-
436+
414437 // Test 1: Final byte 'm' appearing before an intermediate byte '/'
415438 // The RegExp should stop at 'm', leaving the '/' and space behind.
416- const invalidOrder = '\x 1b[m/ ' ;
439+ const invalidOrder = '\x 1b[m/ ' ;
417440 expect (invalidOrder.ansiLength, equals (3 )); // Matches '\x1b[m'
418441 expect (invalidOrder.withoutAnsi, equals ('/ ' ));
419442
@@ -429,18 +452,18 @@ needs to be wrapped.
429452 expect (params.ansiLength, equals (params.length));
430453
431454 // Intermediate Range Character Codes 0x20 - 0x2f [Space ! " # $ % & ' ( ) * + , - . /]
432- final intermediateChars = String .fromCharCodes ([
433- for (var c = 0x20 ; c <= 0x2F ; c++ ) c,
434- ]);
435- final intermediates = '\x 1b[${intermediateChars }m' ;
455+ final intermediateChars = String .fromCharCodes ([
456+ for (var c = 0x20 ; c <= 0x2F ; c++ ) c,
457+ ]);
458+ final intermediates = '\x 1b[${intermediateChars }m' ;
436459 expect (intermediates.ansiLength, equals (intermediates.length));
437460 });
438461
439462 test ('Strictly terminates at the first Final Byte' , () {
440- // In the string below, 'H' is a final byte.
463+ // In the string below, 'H' is a final byte.
441464 // Even though 'm' is also a valid final byte, the sequence must end at 'H'.
442465 const twoFinals = '\x 1b[1H;24m' ;
443-
466+
444467 expect (twoFinals.ansiLength, equals (4 )); // Matches only '\x1b[1H'
445468 expect (twoFinals.withoutAnsi, equals (';24m' ));
446469 });
@@ -476,28 +499,35 @@ needs to be wrapped.
476499 }
477500 });
478501
479- test ('Characters with offsets (ESC, [, parameter, intermediate, terminator)' , () {
502+ test (
503+ 'Characters with offsets (ESC, [, parameter, intermediate, terminator)' ,
504+ () {
480505 final offsets = [0x80 , 0x100 , 0x1000 , 0xd800 , 0x10000 ];
481506 for (var offset in offsets) {
482507 // ESC replaced
483508 var str = '${String .fromCharCode (0x1b + offset )}[0m' ;
484- expect (str.ansiLength, equals (0 ), reason: 'Failed on ESC + 0x${offset .toRadixString (16 )}' );
509+ expect (str.ansiLength, equals (0 ),
510+ reason: 'Failed on ESC + 0x${offset .toRadixString (16 )}' );
485511
486512 // [ replaced
487513 str = '\x 1b${String .fromCharCode (0x5b + offset )}0m' ;
488- expect (str.ansiLength, equals (0 ), reason: 'Failed on [ + 0x${offset .toRadixString (16 )}' );
514+ expect (str.ansiLength, equals (0 ),
515+ reason: 'Failed on [ + 0x${offset .toRadixString (16 )}' );
489516
490517 // Parameter byte replaced
491518 str = '\x 1b[${String .fromCharCode (0x30 + offset )}m' ;
492- expect (str.ansiLength, equals (0 ), reason: 'Failed on param + 0x${offset .toRadixString (16 )}' );
519+ expect (str.ansiLength, equals (0 ),
520+ reason: 'Failed on param + 0x${offset .toRadixString (16 )}' );
493521
494522 // Intermediate byte replaced
495523 str = '\x 1b[0${String .fromCharCode (0x20 + offset )}m' ;
496- expect (str.ansiLength, equals (0 ), reason: 'Failed on intermediate + 0x${offset .toRadixString (16 )}' );
524+ expect (str.ansiLength, equals (0 ),
525+ reason: 'Failed on intermediate + 0x${offset .toRadixString (16 )}' );
497526
498527 // Terminator byte replaced
499528 str = '\x 1b[0${String .fromCharCode (0x6d + offset )}' ;
500- expect (str.ansiLength, equals (0 ), reason: 'Failed on terminator + 0x${offset .toRadixString (16 )}' );
529+ expect (str.ansiLength, equals (0 ),
530+ reason: 'Failed on terminator + 0x${offset .toRadixString (16 )}' );
501531 }
502532 });
503533 });
0 commit comments