@@ -274,81 +274,30 @@ describe("formatTokens", () => {
274274 } ) ;
275275} ) ;
276276
277- describe ( "clampText surrogate-safe truncation" , ( ) => {
278- it ( "does not split an emoji across the truncation boundary" , ( ) => {
279- // 121 UTF-16 units: 119 'a's then an emoji (surrogate pair at 119-120).
280- // With max = 120, naive slice(0, 119) keeps only the emoji's high surrogate.
281- const value = `${ "a" . repeat ( 119 ) } \u{1F600}` ;
282- expect ( value . length ) . toBe ( 121 ) ;
283-
284- const result = clampText ( value , 120 ) ;
285-
286- // The emoji should be entirely dropped, leaving the 119 'a's + "…"
287- expect ( result ) . toBe ( `${ "a" . repeat ( 119 ) } …` ) ;
288- // No dangling surrogates
289- for ( let i = 0 ; i < result . length ; i ++ ) {
290- const cu = result . charCodeAt ( i ) ;
291- if ( cu >= 0xd800 && cu <= 0xdbff ) {
292- expect ( result . charCodeAt ( i + 1 ) >= 0xdc00 && result . charCodeAt ( i + 1 ) <= 0xdfff ) . toBe ( true ) ;
293- }
294- if ( cu >= 0xdc00 && cu <= 0xdfff ) {
295- expect (
296- i > 0 && result . charCodeAt ( i - 1 ) >= 0xd800 && result . charCodeAt ( i - 1 ) <= 0xdbff ,
297- ) . toBe ( true ) ;
298- }
299- }
277+ describe ( "text truncation" , ( ) => {
278+ it ( "keeps clampText output valid when the ellipsis boundary bisects an emoji" , ( ) => {
279+ expect ( clampText ( `${ "a" . repeat ( 118 ) } 😀x` , 120 ) ) . toBe ( `${ "a" . repeat ( 118 ) } …` ) ;
300280 } ) ;
301281
302- it ( "leaves short text unchanged " , ( ) => {
303- expect ( clampText ( "hello" , 120 ) ) . toBe ( "hello" ) ;
304- } ) ;
305-
306- it ( "appends ellipsis when truncated" , ( ) => {
307- expect ( clampText ( "x" . repeat ( 200 ) , 120 ) ) . toMatch ( / … $ / ) ;
282+ it ( "keeps truncateText output valid when the boundary bisects an emoji " , ( ) => {
283+ expect ( truncateText ( ` ${ "a" . repeat ( 120 ) } 😀` , 121 ) ) . toEqual ( {
284+ text : "a" . repeat ( 120 ) ,
285+ truncated : true ,
286+ total : 122 ,
287+ } ) ;
308288 } ) ;
309- } ) ;
310289
311- describe ( "truncateText surrogate-safe truncation" , ( ) => {
312- it ( "does not split an emoji across the truncation boundary" , ( ) => {
313- // 121 UTF-16 units: 120 'a's then an emoji at index 120.
314- const value = `${ "a" . repeat ( 120 ) } \u{1F600}` ;
315- expect ( value . length ) . toBe ( 122 ) ;
316-
317- const result = truncateText ( value , 121 ) ;
318-
319- expect ( result . truncated ) . toBe ( true ) ;
320- // The emoji should be dropped entirely
321- expect ( result . text ) . not . toContain ( "\u{1F600}" ) ;
322- // No dangling surrogates
323- for ( let i = 0 ; i < result . text . length ; i ++ ) {
324- const cu = result . text . charCodeAt ( i ) ;
325- if ( cu >= 0xd800 && cu <= 0xdbff ) {
326- expect (
327- result . text . charCodeAt ( i + 1 ) >= 0xdc00 && result . text . charCodeAt ( i + 1 ) <= 0xdfff ,
328- ) . toBe ( true ) ;
329- }
330- if ( cu >= 0xdc00 && cu <= 0xdfff ) {
331- expect (
332- i > 0 &&
333- result . text . charCodeAt ( i - 1 ) >= 0xd800 &&
334- result . text . charCodeAt ( i - 1 ) <= 0xdbff ,
335- ) . toBe ( true ) ;
336- }
337- }
338- } ) ;
339-
340- it ( "returns truncated: false for short text" , ( ) => {
290+ it ( "leaves short text unchanged" , ( ) => {
291+ expect ( clampText ( "hello" , 120 ) ) . toBe ( "hello" ) ;
341292 expect ( truncateText ( "hello" , 120 ) ) . toEqual ( {
342293 text : "hello" ,
343294 truncated : false ,
344295 total : 5 ,
345296 } ) ;
346297 } ) ;
347298
348- it ( "reports correct total for truncated text" , ( ) => {
349- const result = truncateText ( "x" . repeat ( 200 ) , 120 ) ;
350- expect ( result . truncated ) . toBe ( true ) ;
351- expect ( result . total ) . toBe ( 200 ) ;
352- expect ( result . text . length ) . toBeLessThan ( 200 ) ;
299+ it ( "preserves ordinary truncation behavior" , ( ) => {
300+ expect ( clampText ( "abc" , 2 ) ) . toBe ( "a…" ) ;
301+ expect ( truncateText ( "abc" , 2 ) ) . toEqual ( { text : "ab" , truncated : true , total : 3 } ) ;
353302 } ) ;
354303} ) ;
0 commit comments